## IMPORTATIONS
import pandas as pd
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)
idx = pd.IndexSlice
import string
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline
import seaborn as sns
sns.set_style("whitegrid")
#% matplotlib notebook
# graphes interactifs
import re
from wordcloud import WordCloud, STOPWORDS
from collections import Counter
from IPython.display import Image
import scipy.stats as st
#import statsmodels.api as sm
#from sklearn.datasets import load_iris
#iris_df_ori = load_iris()
#### A ESSAYER #######################################################
# GRAPHES INTERACTIFS
# POUR LES GRAPHIQUES
# % matplotlib inline
# plt.rcParams['figure.figsize'] = [9.5, 6] # ajuster la taille
# POUR DESACTIVER LA TOOLBOX GRAPHES TOP GRANDS
# %%javascript
# IPython.OutputArea.prototype._should_scroll = function(lines) {
# return false;
# }
## FONCTION SORTANT UN DATAFRAME D'INFOS (complémentaire du describe)
def desc_bis (df):
nb_li = df.index.size
nb_col = df.columns.size
tot = nb_li*nb_col
infos = pd.DataFrame(df.dtypes).T.rename(index={0:'Type'})
infos = infos.append(pd.DataFrame(df.isna().sum()).T.rename(index={0:'null'}))
return infos
def infos (df):
nb_li = df.shape[0]
nb_co = df.shape[1]
t = np.empty(nb_li)
t.fill(nb_li)
df_l_null = pd.DataFrame(df.T.isna().sum()) # tableau du nbe de nul par lignes (+800 000 lignes)
df_c_null = pd.DataFrame(df.isna().sum()) # tableau du nbe de nul par colonnes (+65 colonnes)
# nbe de lignes sans 'null'
al = len([x for x in df_l_null[0] if x==0])
nb_ss_null = pd.DataFrame([al]).rename(index={0:'lign_ss_null'}).T
pct_ss_null = pd.DataFrame([al*100/nb_li]).rename(index={0:'lign_ss_null'}).T
# nbe de lignes 'null'
bl = len([x for x in df_l_null[0] if x==nb_co])
nb_null = pd.DataFrame([bl]).rename(index={0:'lign_null'}).T
pct_null = pd.DataFrame([bl*100/nb_li]).rename(index={0:'lign_null'}).T
# nbe de lignes mixtes
cl = len([x for x in df_l_null[0] if (x!=0 and x!=nb_co)])
nb_mix = pd.DataFrame([cl]).rename(index={0:'lign_mix'}).T
pct_mix = pd.DataFrame([cl*100/nb_li]).rename(index={0:'lign_mix'}).T
infos_nb = pd.concat([nb_ss_null, nb_null, nb_mix],axis=1, sort=False).rename(index={0:'nb'})
infos_pct = pd.concat([pct_ss_null, pct_null, pct_mix],axis=1, sort=False).rename(index={0:'pct'})
infos_l = pd.concat([infos_nb,infos_pct], sort=False)
# nbe de lignes total
infos_l["lign_tot"] = [infos_l.T['nb'].sum(), infos_l.T['pct'].sum()]
# nbe de colonnes sans 'null'
ac = len([x for x in df_c_null[0] if x==0])
nb_ss_null = pd.DataFrame([ac]).rename(index={0:'col_ss_null'}).T
pct_ss_null = pd.DataFrame([ac*100/nb_co]).rename(index={0:'col_ss_null'}).T
# nbe de colonnes 'null'
bc = len([x for x in df_c_null[0] if x==nb_li])
nb_null = pd.DataFrame([bc]).rename(index={0:'col_null'}).T
pct_null = pd.DataFrame([bc*100/nb_co]).rename(index={0:'col_null'}).T
# nbe de colonnes mixtes
cc = len([x for x in df_c_null[0] if (x!=0 and x!=nb_li)])
nb_mix = pd.DataFrame([cc]).rename(index={0:'col_mix'}).T
pct_mix = pd.DataFrame([cc*100/nb_co]).rename(index={0:'col_mix'}).T
infos_nb = pd.concat([nb_ss_null, nb_null, nb_mix],axis=1, sort=False).rename(index={0:'nb'})
infos_pct = pd.concat([pct_ss_null, pct_null, pct_mix],axis=1, sort=False).rename(index={0:'pct'})
infos_c = pd.concat([infos_nb,infos_pct], sort=False)
# nbe de lignes total
infos_c["col_tot"] = [infos_c.T['nb'].sum(), infos_c.T['pct'].sum()]
infos = pd.concat([infos_l,infos_c], axis=1, sort=False)
return infos
## FONCTION DE COMPTAGE DES VALEURS NULLES
def evalNull (inf_df):
a = inf_df.T['null'].sum()
b = inf_df.T['count'].sum()
print("Nbe valeurs 'null' : {:.0f}".format(a))
print("Nbe valeurs non 'null' : {:.0f}".format(b))
print("Nbe total cases : {:.0f}".format(a+b))
print("% total valeurs 'null' : {:.1f}%".format(a*100/(a+b)))
# Fonction qui trouve les éléments uniques différents dans deux tableaux
def Diff(tab1, tab2):
#tab_dif = [i for i in tab1 + tab2 if i not in tab1 or i not in tab2] # renvoie en vrac toutes les entrées spécifiques
return (set(tab1)-set(tab2),set(tab2)-set(tab1)) # renvoie deux tableaux spécifiques à tab1 puis tab2
# Fonction vérifiant l'unicité des lignes d'une liste de listes
def uniCle (t_tab):
if isinstance(t_tab[0], type(str)) :
uni = list(set(t_tab))
res = True if (len(uni)==len(t_tab)) else False
else :
uni = list(set(zip(*t_tab))) # liste des combinaisons uniques
res = True if (len(uni)==len(t_tab[0])) else False
return res
# Fonction comparant la correspondance unique entre les valeurs d'une même ligne de deux colonnes d'une base
# (bijection entre les valeurs de col1 et de col2)
def Adeq (df, nom_col1,nom_col2):
mon_zip = zip(df[nom_col1], df[nom_col2]) # associe les entrées des deux colonnes en tuples
nbe_comb = len(set(mon_zip)) # retourne les valeurs uniques des tuples
return nbe_comb==df[nom_col1].unique().size # si le nbe est le même que les valeurs uniques, c'est bon
def recursive_len(item):
if type(item) == list:
return sum(recursive_len(subitem) for subitem in item)
else:
return 1
def contAny (cars, mot):
return any([True if c in cars else False for c in mot])
def contAll (cars, mot):
return all([True if c in cars else False for c in mot])
def enum_mots_cmpt(li_phrases, nb): # prend une liste de phrases en entrée
li_mots = " ".join(li_phrases).split(" ")
li_mots_net = sorted([mot for mot in li_mots if (mot != '') \
and not contAll('-)%.(,', mot)])
cpt = Counter(li_mots_net)
words_occ = cpt.most_common(nb) # tableau de tuples
words = [words_occ[i][0] for i in range(len(words_occ))]
occs = [words_occ[i][1] for i in range(len(words_occ))]
dic_occs = dict()
for i in range(len(words_occ)):
dic_occs[words[i]]=occs[i]
return dic_occs # dictionnaire
def filt_dict(dic_t, li_pop):
dic = dic_t
[dic.pop(w) for w in li_pop if w in dic_t.keys()]
return dic
def random_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
h = int(360.0 * tone / 255.0)
s = int(100.0 * 255.0 / 255.0)
l = int(100.0 * float(np.random.randint(70, 120) / 255.0))
return "hsl({}, {}%, {}%)".format(h, s, l)
tone = 10.0 # define the color of the words
def nuageMots(dic_occs): # prend un dictionnaire {"mot" : nbe occurences}
fig = plt.figure(figsize=(18,8))
wordcloud = WordCloud(width=1000,height=200, background_color='black', max_words=1628,\
relative_scaling=1, color_func = None, normalize_plurals=False)
wordcloud.generate_from_frequencies(dic_occs)
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis('off')
plt.show()
def histMots(dic_occs): # prend un dictionnaire {"mot" : nbe occurences}
fig = plt.figure(figsize=(18,4))
tab_occs = np.array([[k,int(v)] for k,v in dic_occs.items()]).T # dictionnaire en tableau
x = tab_occs[0]
y = tab_occs[1].astype(int)
x_label = tab_occs[0]
ax = plt.bar(x, y, align = 'center', color='b')
plt.xticks(x, x_label, rotation=85, fontsize = 15)
plt.yticks(fontsize = 15)
plt.ylabel("Nb. of occurences", fontsize = 18, labelpad = 10)
plt.title("Fréquence des mots-clés",color='k',fontsize = 18, fontweight = 'bold')
plt.show() # affiche l'histogramme
## FONCTION D'AFFICHAGE
def basic_plot(plot_type, my_plot, my_x, my_y, my_x_t, xlab, ylab, my_tit, num_col):
if plot_type == "plot" :
my_plot.plot(my_x, my_y, '-o', color = colors[num_col])
elif plot_type == "bar" :
my_plot.bar(my_x, my_y, color = colors[num_col])
elif plot_type == "scatter" :
my_plot.scatter(my_x, my_y, color = colors[num_col])
else :
print("erreur type de graphe")
my_plot.set_xlabel(xlab, fontsize = 14)
my_plot.set_ylabel(ylab, fontsize = 14)
if my_x_t == '':
plt.xticks(fontsize = 14)
else :
plt.xticks(my_x_t, my_x_t, rotation=85 , fontsize = 14)
plt.yticks(fontsize = 14)
plt.ylim(round(min(my_y)*0.9), round(max(my_y)*1.1))
my_plot.set_title(my_tit, fontsize = 18, fontweight = 'bold')
plt.grid(color='grey', linestyle='dotted')
L'ensemble des données téléchargées se compose de 5 fichiers .csv et d'un fichier excel comportant 5 onglets. Il semble que l'intégralité des données des fichiers .csv soit reprise dans chacun des onglets du fichier Excel.
Dans ce notebook, on appellera "base de donnée" l'ensemble des données, et "table" chacun des onglets ou fichier .csv correspondant.
On travaillera sur les cinq dataframes créées dans la cellule suivante :
# Utilisé la fonction dropna (colonne nulle) pour éliminer les colonnes fantômes "Unamed en fin de tableau"
data = pd.read_csv("../DONNEES/EdStatsData.csv").dropna(how='all', axis='columns')
country = pd.read_csv("../DONNEES/EdStatsCountry.csv").dropna(how='all', axis='columns')
cnt_ser = pd.read_csv("../DONNEES/EdStatsCountry-Series.csv").dropna(how='all', axis='columns')
series = pd.read_csv("../DONNEES/EdStatsSeries.csv").dropna(how='all', axis='columns')
footnote = pd.read_csv("../DONNEES/EdStatsFootNote.csv").dropna(how='all', axis='columns')
On crée 5 nouvelles dataframes "data_c", "country_c", "series_c", "cnt_ser_c" et "footnote_c" qui contiendront les données rectifiées :
# on crée d'autres dataframes à modifier (deep copies)
data_c = data.copy()
country_c = country.copy()
series_c = series.copy()
cnt_ser_c = cnt_ser.copy()
footnote_c = footnote.copy()
## COMPTAGE DES 'NULL' par LIGNES et par COLONNES (toutes les tables)
infos_t = pd.concat([infos(data), infos(country), infos(series),\
infos(cnt_ser), infos(footnote)], axis = 0,\
keys=['data', 'country', 'series', 'cnt_ser', 'footnote'])
pd.options.display.float_format = '{:.1f}'.format
infos_t
inf_data = desc_bis(data).append(data.describe(include='all'))
evalNull(inf_data)
inf_data
inf_country = desc_bis(country).append(country.describe(include='all'))
evalNull(inf_country)
inf_country
inf_series = desc_bis(series).append(series.describe(include='all'))
evalNull(inf_series)
inf_series
inf_cnt_ser = desc_bis(cnt_ser).append(cnt_ser.describe(include='all'))
evalNull(inf_cnt_ser)
inf_cnt_ser
inf_footnote = desc_bis(footnote).append(footnote.describe(include='all'))
evalNull(inf_footnote)
inf_footnote
L'analyse de la composition des tables a permis de déduire le MPD (Modèle Physique de Données) de la base représenté ci-dessous :
Image("../UML/EduStatsMPD.png")
Les clés proposées dans le MPD ci-dessus pour chaque jeu faciliteraient l'utilisation de la base, sous réserve de quelques modifications (voir modifications plus bas) :
La description ci-dessus nous a permis de déterminer les colonnes de chaque bases susceptibles de jouer le rôle de clés. Afin de faciliter l'exploitation de la base, il est important que la clé de chaque table soit unique. Vérifions donc que les tables sont exemptes de doublons :
print("Table Data : Unicité de la clé ('Country Code'&'Indicator Code') {}"\
.format(uniCle([data["Country Code"], data["Indicator Code"]])))
print("Table Country : Unicité de la clé ('Country Code') {}"\
.format(uniCle(country["Country Code"])))
print("Table Series : Unicité de la clé ('Series Code') {}"\
.format(uniCle(series["Series Code"])))
print("Table Country-Series : Unicité de la clé ('CountryCode'&'SeriesCode') {}"\
.format(uniCle([cnt_ser["CountryCode"], cnt_ser["SeriesCode"]])))
print("Table FootNote : Unicité de la clé ('CountryCode'&'SeriesCode'&'Year') {}"\
.format(uniCle([footnote["CountryCode"],footnote["SeriesCode"],footnote["Year"]])))
Les tables sont bien exemptes de doublons. Pour plus de clarté, on renomme les colonnes contenant des entrées apparentées :
country_c.rename(columns={'Table Name':'Country Name'}, inplace=True)
series_c.rename(columns={'Series Code':'Indicator Code'}, inplace=True)
cnt_ser_c.rename(columns={'CountryCode':'Country Code',
'SeriesCode':'Indicator Code',
'DESCRIPTION':'Desc Data'}, inplace=True)
footnote_c.rename(columns={'CountryCode':'Country Code',
'SeriesCode':'Indicator Code',
'DESCRIPTION':'Footnote Data'}, inplace=True)
cnt_lack = Diff(list(data["Country Code"].unique()),list(country["Country Code"].unique()))
print("Codes des pays spécifiques à 'Data' : {}"\
.format(cnt_lack[0]))
print("Codes des pays spécifiques à 'Country' : {}"\
.format(cnt_lack[1]))
code = list(cnt_lack[0])[0]
nom = list(data[data["Country Code"]==(list(cnt_lack[0])[0])]["Country Name"].unique())[0]
print("Code et nom du pays à ajouter : {},{}".format(code, nom))
La table Country étant supposée renseigner sur tous les pays présents dans la base, on rajoute une ligne dans la base "Country" contenant le pays manquant :
line_vgb = pd.DataFrame([[code]+[None]+[nom]+[None]*(country_c.columns.size-3)],\
columns = country_c.columns) # ligne à ajouer
country_c = country_c.append(line_vgb,'sort=False') # ajout en bas de la liste
country_c = country_c.sort_values("Country Code") # remet les lignes en ordre alphabétique de pays
country_c.index = list(np.arange(country_c.index.size)) # renumérote l'index
#country_c.drop_duplicates(subset='Country Name', keep='first', inplace=True)
cnt_lack = Diff(list(data_c["Country Name"].unique()),list(country_c["Country Name"].unique()))
print("* Noms des pays spécifiques à 'Data' : {}"\
.format(sorted(cnt_lack[0])))
print("----------------")
print("* Noms des pays spécifiques à 'Country' : {}"\
.format(sorted(cnt_lack[1])))
print("----------------")
print("* Nombre de pays non concordants : {}, {}".format(len(cnt_lack[0]), len(cnt_lack[1])))
# liste complète des codes des pays posant problème (data, puis country) :
l_data = sorted([data_c[data_c["Country Name"]==nom_col].iloc[0]["Country Code"] for nom_col in cnt_lack[0]])
l_country = sorted([country_c[country_c["Country Name"]==nom_col].iloc[0]["Country Code"] for nom_col in cnt_lack[1]])
l_pbe = sorted(list(set(l_data + l_country)))
print("----------------")
print("* Liste des codes des {} pays posant problème : {}".format(len(l_pbe), l_pbe))
# tableau comparatif des noms de pays 'posant problème' et ayant le même code dans data et country
mask1 = [li.any() for li in np.array([np.array((data["Country Code"]==n).values) for n in l_pbe]).T]
mask2 = [li.any() for li in np.array([np.array((country["Country Code"]==n).values) for n in l_pbe]).T]
comp = pd.merge(data[mask1], country[mask2], left_on= "Country Code", right_on= "Country Code")
tab_ser = [comp[comp["Country Code"] == pays].iloc[0][['Country Code','Country Name', 'Table Name']] \
for pays in l_pbe]
my_df = pd.DataFrame(tab_ser, columns = ['Country Code','Country Name', 'Table Name'])
my_df.columns = ['Country Code','Country Name (data_c)', 'Country Name (country_c)' ]
my_df.sort_values(by = ['Country Name (country_c)'], ascending = True, inplace = True)
my_df = my_df.reset_index(drop=True)
my_df.head()
On conserve les noms de la table 'Data', qui ne contiennent pas de caractères spéciaux, et qui sont plus clairs sur la désignation ('excluding high income' préférable à 'all income levels') :
country_c["Country Name"].replace(to_replace = my_df['Country Name (country_c)'].values, \
value = my_df['Country Name (data_c)'].values, inplace=True)
serie_lack = Diff(list(data_c["Indicator Code"].unique()),list(series_c["Indicator Code"].unique()))
print("Nbe d'indicateurs spécifiques à 'Data' : {}"\
.format(len(serie_lack[0])))
print("Nbe d'indicateurs spécifiques à 'Series' : {}"\
.format(len(serie_lack[1])))
print("Quelques indicateurs spécifiques à 'Data' :\n {}"\
.format(sorted(serie_lack[0])[:5]))
print("Quelques indicateurs spécifiques à 'Series' :\n {}"\
.format(sorted(serie_lack[1])[:5]))
L'échantillon d'indicateurs affichés ci-dessus ne diffèrent en fait que par 1) des espaces 2) des lettres en minuscule dans la table "Series". Vérifions qu'après correction les entrées sont les mêmes :
test_ser = pd.Series([series["Series Code"][i].upper().replace(" ", "")\
for i in range(series["Series Code"].index.size)],\
index = series["Series Code"].index)
test_data = pd.Series([data["Indicator Code"][i].upper().replace(" ", "")\
for i in range(data["Indicator Code"].index.size)],\
index = data["Indicator Code"].index)
lack1 = Diff(list(data["Indicator Code"].unique()),list(test_ser.unique()))
lack2 = Diff(list(test_data.unique()), list(series["Series Code"].unique()))
lack3 = Diff(list(test_data.unique()), list(test_ser.unique()))
print("-----Correction de 'Series' seule :-----")
print("Nbe d'indicateurs spécifiques à 'Data', puis 'Series' : {}, {}"\
.format(len(lack1[0]), len(lack1[1])))
print("-----Correction de 'Data' seule :-----")
print("Nbe d'indicateurs spécifiques à 'Data', puis 'Series' : {}, {}"\
.format(len(lack2[0]), len(lack2[1])))
print("-----Correction de 'Data' et 'Series' :-----")
print("Nbe d'indicateurs spécifiques à 'Data', puis 'Series' : {}, {}"\
.format(len(lack3[0]), len(lack3[1])))
La correction des noms des deux bases est nécessaire. On effectue la correction des indicateurs dans la base 'Data', dans la base 'Series'.
data_c["Indicator Code"].replace(to_replace = serie_lack[0], \
value = [x.upper().replace(" ", "") for x in serie_lack[0]], inplace=True)
series_c["Indicator Code"].replace(to_replace = serie_lack[1], \
value =[x.upper().replace(" ", "") for x in serie_lack[1]], inplace=True)
serie_lack2 = Diff(list(data_c["Indicator Code"].unique()),list(series_c["Indicator Code"].unique()))
print("Nbe d'indicateurs spécifiques à 'Data' et à 'Series' après modification : {}, {}"\
.format(len(serie_lack2[0]),len(serie_lack2[1])))
cnt_ser_lack1 = Diff(list(series_c["Indicator Code"].unique()),list(cnt_ser_c["Indicator Code"].unique()))
cnt_ser_lack2 = Diff(list(country_c["Country Code"].unique()),list(cnt_ser_c["Country Code"].unique()))
footnote_lack1 = Diff(list(series_c["Indicator Code"].unique()),list(footnote_c["Indicator Code"].unique()))
footnote_lack2 = Diff(list(country_c["Country Code"].unique()),list(footnote_c["Country Code"].unique()))
print("-------- table 'CountrySeries' --------")
print("Nbe d'indicateurs/de pays spécifiques à 'Series'/'Country' : {}/{}"\
.format(len(cnt_ser_lack1[0]), len(cnt_ser_lack2[0])))
print("Nbe d'indicateurs/de pays spécifiques à 'CountrySeries' : {}/{}"\
.format(len(cnt_ser_lack1[1]), len(cnt_ser_lack2[1])))
print("-------- table 'FootNote' --------")
print("Nbe d'indicateurs/de pays spécifiques à 'Series'/'Country' : {}/{}"\
.format(len(footnote_lack1[0]), len(footnote_lack2[0])))
print("Nbe d'indicateurs/de pays spécifiques à 'FootNote' : {}/{}"\
.format(len(footnote_lack1[1]), len(footnote_lack2[1])))
La base 'CountrySeries' ne contient ni de code de pays ni de code d'indicateur qui ne soit pas dans les bases 'Country' et 'Series', en revanche, la base 'FootNote' contient des codes d'indicateurs erronnés.
print("-------------")
# pays pas dans footnote,
#print("Quelques code pays seulement dans footnote :\n{}".format(list(footnote_lack2[0])[:15]))
#pays seulement dans footnote
print("Quelques code pays seulement dans footnote :\n{}".format(list(footnote_lack2[1])[:5]))
print("-------------")
# codes indicateurs pas dans footnote,
#print("Quelques indicateurs de 'series' pas dans 'footnote' :\n{}".format(list(footnote_lack1[0])[:3]))
#codes indicateurs seulement dans footnote
print("Quelques indicateurs seulement dans 'footnote' :\n{}".format(list(footnote_lack1[1])[:25]))
Les codes d'indicateurs de 'FootNote' contiennent des lettres en minuscules. On applique la même modification que pour les tables 'Data' et 'Series' précédemment (élimination des espaces, passage en majuscules). On vérifie qu'après correction 'FootNote' n'a pas de codes d'indicateurs spécifiques.
footnote_c["Indicator Code"].replace(to_replace = footnote_lack1[1], \
value = [x.upper().replace(" ", "") for x in footnote_lack1[1]], inplace=True)
footnote_lack = Diff(list(footnote_c["Indicator Code"].unique()),list(series_c["Indicator Code"].unique()))
print("Nbe d'indicateurs spécifiques à 'Data' et à 'Series' après modification : {}, {}"\
.format(len(footnote_lack[0]),len(footnote_lack[1])))
On remarque que 462 entrées uniques de la colonne "Indicator Name" de la table "data" ne sont pas dans la table "series" et que le même nombre 462 d'entrées uniques de la même colonne de la table "series" ne sont pas dans la table "data".
indic_lack = Diff(list(data_c["Indicator Name"].unique()),list(series["Indicator Name"].unique()))
#noms d'indicateurs seulement dans data
print("Quelques indicateurs seulement dans 'Data' :\n{}".format(list(indic_lack[0])[:3]))
#noms d'indicateurs seulement dans series
print("Quelques indicateurs seulement dans 'Series' :\n{}".format(list(indic_lack[1])[:3]))
print("----------------")
print("* Nombre de pays non concordants : {}, {}".format(len(indic_lack[0]), len(indic_lack[1])))
# liste complète des codes des indicateurs posant problème (data, puis series) :
l_data = sorted([data_c[data_c["Indicator Name"]==nom_col].iloc[0]["Indicator Code"] for nom_col in indic_lack[0]])
l_series = sorted([series_c[series_c["Indicator Name"]==nom_col].iloc[0]["Indicator Code"] for nom_col in indic_lack[1]])
l_pbe = sorted(list(set(l_data + l_series)))
print("----------------")
print("* Liste des codes de quelques-uns des {} indicateurs posant problème : {}".format(len(l_pbe), l_pbe[:3]))
# tableau comparatif des noms de pays 'posant problème' et ayant le même code dans data et series
mask1 = [li.any() for li in np.array([np.array((data_c["Indicator Code"]==n).values) for n in l_pbe]).T]
mask2 = [li.any() for li in np.array([np.array((series_c["Indicator Code"]==n).values) for n in l_pbe]).T]
comp = pd.merge(data_c[mask1], series_c[mask2], left_on= "Indicator Code", right_on= "Indicator Code")
tab_ser = [comp[comp["Indicator Code"] == ind].iloc[0][['Indicator Code','Indicator Name_x', 'Indicator Name_y']] \
for ind in l_pbe]
# Affichage des noms complets
# comp[['Indicator Code','Indicator Name_x', 'Indicator Name_y', 'Country Name']]\
# .groupby(['Indicator Code','Indicator Name_x','Indicator Name_y']).count()
my_df = pd.DataFrame(tab_ser, columns = ['Indicator Code','Indicator Name_x', 'Indicator Name_y'])
my_df.columns = ['Indicator Code','Indicator Name (data_c)', 'Indicator Name (series_c)' ]
my_df.sort_values(by = ['Indicator Name (series_c)'], ascending = True, inplace = True)
#my_df = my_df.reset_index(drop=True)
my_df.head()
Les noms de la table 'Series' sont généralement plus complets que ceux de 'Data'. On remplace donc les valeurs de 'Indicator Name' dans 'data_c' par celles de la même colonne dans 'series_c' :
############# A FAIRE #########################
# Remplacement par le nom le plus long des deux
# Vérifier quand même que des indicateurs plus courts n'ont pas été remplacés par des plus longs !!!!
#################################################""""""
# remplacement des noms de la colonne data, par ceux de la colonne series
data_c["Indicator Name"].replace(to_replace = my_df['Indicator Name (data_c)'].values, \
value = my_df['Indicator Name (series_c)'].values, inplace=True)
#Vérification de la correspondance après modification
verif = Diff(sorted(data_c["Indicator Name"].unique()), sorted(series_c["Indicator Name"].unique()))
list(verif[0])[:5], list(verif[1])[:5]
len(data_c["Indicator Name"].unique()), len(series_c["Indicator Name"].unique())
############# A FAIRE #########################
# Fusion des tables footnote_c et cnt_ser_c en une table inf_data_c
#################################################
# liste des années de la colonne "Year" de la table "FootNote"
print(set(footnote_c["Year"].unique()))
On remplace les valeurs des chaînes par l'entier correspondant :
# remplacement des années de la colonne 'Year', par les nombres correspondants
ch_ann_uni = list(footnote_c["Year"].unique())
int_ann_uni = [int(('').join(re.findall("[0-9]", chaine))) for chaine in ch_ann_uni]
footnote_c["Year"].replace(to_replace = ch_ann_uni, value = int_ann_uni, inplace=True)
print(set(footnote_c["Year"].unique()))
Après vérification de l'unicité des clés choisies pour chaque table, on vérifie la correspondance bijective entre plusieurs paires de colonnes d'une même table, par exemple :
On teste (voir définition de la fonction 'Adeq' plus haut) les couples de colonnes listés ci-dessous :
print("Data : {} {}"\
.format(Adeq(data_c, "Country Code", "Country Name"), Adeq(data_c, "Indicator Code", "Indicator Name")))
print("Country : {} {} {}"\
.format(Adeq(country_c, "Country Code", "Short Name"), Adeq(country_c, "Country Code", "Country Name"),\
Adeq(country_c, "Country Code", "Long Name")))
print("Series : {}".format(Adeq(series_c, "Indicator Code", "Indicator Name")))
Pour faciliter le traitement ultérieur des données de la table "Data", on ajoute deux colonnes précisant :
# ajout de la région du pays
data_c = pd.merge( data_c , country_c[['Country Code', 'Region']] , left_on = 'Country Code', right_on = 'Country Code' )
# ajout du topic de l'indicateur
data_c = pd.merge( data_c , series_c[['Indicator Code', 'Topic']] , left_on = 'Indicator Code', right_on = 'Indicator Code' )
cols = list(data_c.columns.values)
cols = cols[-2:]+cols[:-2]
data_c = data_c[cols] # remise en ordre des colonnes
Il existe des colonnes dans les tables 'Country', 'Series', 'Country-Series' et 'Footnote' qui sont très peu remplies. Cependant, les données contenues dans ces tables ne sont pas indispensables au traitement des données chiffrées, qui sont contenues dans la table 'Data'. On n'éliminera donc pas ces colonnes. En ce qui concerne la table 'Data', elle contient seulement deux colonnes peu remplies (années 2016 et 2017) qu'il n'est pas nécessaire d'effacer pour l'instant.
# comptage des pays uniques sans région
sans_reg_cnt = country_c[country_c["Region"].isna()]["Country Name"]
li_pays_supp = sans_reg_cnt.values
#['Arab World', 'East Asia & Pacific (excluding high income)','East Asia & Pacific', 'Europe & Central Asia (excluding high income)', 'Europe & Central Asia', 'Euro area', 'European Union', 'Gibraltar', 'High income', 'Heavily indebted poor countries (HIPC)', 'Latin America & Caribbean (excluding high income)', 'Latin America & Caribbean', 'Least developed countries: UN classification', 'Low income', 'Lower middle income', 'Low & middle income', 'Middle East & North Africa', 'Middle income', 'Middle East & North Africa (excluding high income)', 'North America', 'Nauru', 'OECD members', 'South Asia', 'Sub-Saharan Africa (excluding high income)', 'Sub-Saharan Africa', 'Upper middle income', 'British Virgin Islands', 'World']
print(Diff(sans_reg_cnt, sans_reg_cnt) , len(sans_reg_cnt))
print(li_pays_supp) # faux 'pays' à éliminer
# élimination des faux 'pays' dans "Country"
ind_supp_cnt = sans_reg_cnt.index # index des lignes du tableau country à éliminer (une seule par nom)
country_c.drop(index = ind_supp_cnt, inplace = True)
# élimination des faux 'pays' dans "Data"
sans_reg_data = [data_c[data_c["Country Name"]== col].index for col in li_pays_supp] # liste de listes d'index à retirer
ind_supp_data = [item for sublist in sans_reg_data for item in sublist] # liste des index (applatie)
data_c.drop(index = ind_supp_data, inplace = True)
# vérification
sans_reg_cnt = country_c[country_c["Region"].isna()]["Country Name"]
len(sans_reg_cnt)
sans_reg_cnt = country_c[country_c["Region"].isna()]["Country Name"]
sans_reg_data = data_c[data_c["Region"].isna()]["Country Name"]
print(len(sans_reg_cnt))
fig = plt.figure(figsize = (18,3))
colors = ["#bd5db0","#70a845","#727bcc","#b49242","#cc566c","#4aad92","#ca6037"]
li_annees = inf_data.columns[4:]
x=li_annees
xlab=[my_str[:11]+"..." if len(my_str)>11 else my_str for my_str in x]
y1=inf_data[li_annees].loc["null"]*100/data_c.shape[0] # % de valeurs nulles
y2=inf_data[li_annees].loc["count"] # nombre de valeurs
plot1 = plt.subplot(1,2,1)
basic_plot("bar", plot1, xlab, y1, xlab[::4], "", "% NaN", "% Données manquantes\n(Data)", 0)
plot2 = plt.subplot(1,2,2)
basic_plot("bar", plot2, xlab, y2, xlab[::4], "", "Nbe non nul", "Nbe d'entrées\n(Data)", 1)
plt.show()
# nbe de remplissage minimum/maximum et année correspondante
sel_data = inf_data.loc["count"][4:]
val_min = sel_data.min()
val_max = sel_data.max()
print("- année nbe entrées min, nbe entrées min : \n{}, \n{:.0f}, soit {:.3f}%"\
.format(sel_data.index[sel_data==val_min], \
val_min, val_min*100/(data.shape[0])))
print("- année nbe entrées max, nbe entrées max : \n{}, \n{:.0f}, soit {:.3f}%"\
.format(sel_data.index[sel_data==val_max], \
val_max, val_max*100/(data.shape[0])))
fig = plt.figure(figsize = (18,3))
x=inf_country.columns
xlab=[my_str[:11]+"..." if len(my_str)>11 else my_str for my_str in x]
y1=inf_country.loc["null"]*100/country.shape[0] # % de valeurs nulles
y2=inf_country.loc["count"] # nombre de valeurs
plot1 = plt.subplot(1,2,1)
basic_plot("bar", plot1, xlab, y1, xlab, "", "% NaN", "% Données manquantes\n(Country)", 0)
plot2 = plt.subplot(1,2,2)
basic_plot("bar", plot2, xlab, y2, xlab, "", "Nbe non nul", "Nbe d'entrées\n(Country)", 1)
plt.show()
fig = plt.figure(figsize = (18,3))
x=inf_series.columns
xlab=[my_str[:11]+"..." if len(my_str)>11 else my_str for my_str in x]
y1=inf_series.loc["null"]*100/series.shape[0] # % de valeurs nulles
y2=inf_series.loc["count"] # nombre de valeurs
plot1 = plt.subplot(1,2,1)
basic_plot("bar", plot1, xlab, y1, xlab, "", "% NaN", "% Données manquantes\n(Series)", 0)
plot2 = plt.subplot(1,2,2)
basic_plot("bar", plot2, xlab, y2, xlab, "", "Nbe non nul", "Nbe d'entrées\n(Series)", 1)
plt.show()
print("la table 'CountrySeries' contient {} entrées nulles".format(inf_cnt_ser.loc["null"].sum()))
print("la table 'FootNote' contient {} entrées nulles".format(inf_footnote.loc["null"].sum()))
fig = plt.figure(figsize = (18,5))
grid = plt.GridSpec(1, 3, wspace=0.3, hspace=0.3)
df1 = country_c[['Country Name', 'Region']].groupby('Region').count()
df2 = series_c[['Indicator Name', 'Topic']].groupby('Topic').count()
li_region = list(df1.index)
li_topic = list(df2.index)
x1 = li_region
x2 = li_topic
xlab1 = [my_str[:10]+"..." if len(my_str)>8 else my_str for my_str in x1]
xlab2 = [my_str[:10]+"..." if len(my_str)>8 else my_str for my_str in x2]
y1 = df1.values.reshape(len(df1.values),)
y2 = df2.values.reshape(len(df2.values),)
### Nombre de pays par région
plot1 = plt.subplot(grid[0, 0])
# basic_plot("bar", plot1, xlab1, y1, xlab1, "", "Région", "Nombre de pays par région", 5)
plot1.bar(xlab1, y1, color = colors[1])
plt.xticks(xlab1, rotation=85 , fontsize = 14), plt.yticks(fontsize = 14)
plt.ylim(round(min(y1)*0.9), round(max(y1)*1.1))
plot1.set_title("Nombre de pays par région", fontsize = 18, fontweight = 'bold')
plot1.set_xlabel("Region", fontsize = 14), plot1.set_ylabel("Nbe de pays", fontsize = 14)
labels = [ '{:.0f} pays'.format(y1[i]) for i in range(len(y1))]
for label,xlab1, y1 in zip(labels, xlab1, y1):
plot1.annotate(label, xy=(xlab1, y1), xytext=(-17, 3),
textcoords='offset points', ha='left', va='bottom' )
plt.grid(color='grey', linestyle='dotted')
### Nombre d'indicateurs par topic
plot2 = plt.subplot(grid[0, 1:])
# basic_plot("bar", plot2, xlab2, y2, xlab2, "", "Topic", "Nombre d'indicateur par topic", 4)
plot2.bar(xlab2, y2, color = colors[2])
plt.xticks(xlab2, rotation=85 , fontsize = 14), plt.yticks(fontsize = 14)
plot2.set_title("Nombre d'indicateurs par topic", fontsize = 18, fontweight = 'bold')
plot2.set_xlabel("Topic", fontsize = 14), plot2.set_ylabel("Nbe d'indicateurs'", fontsize = 14)
labels = [ '{:.0f}'.format(y2[i]) for i in range(len(y2))]
for label,xlab2, y2 in zip(labels, xlab2, y2):
plot2.annotate(label, xy=(xlab2, y2), xytext=(-10, 0),
rotation = 0, textcoords='offset points', ha='left', va='bottom' )
plt.grid(color='grey', linestyle='dotted')
plt.show()
Les indicateurs qui nous intéressent sont ceux des dernières années. On cherche à savoir :
### Heatmap du nombre d'indicateurs non nuls (pays/années)
nb_ind_cnt = data_c.groupby(['Country Name']).count()[li_annees]
# Tableau des nombres d'indicateurs dispo pour chaque pays et chaque année
fig = plt.figure(figsize = (28,20))
heat_map = sns.heatmap(nb_ind_cnt)
# tableau du pourcentage d'indicateurs renseignés par pays ()
fig1 = plt.figure(figsize = (30,10))
gp = data_c.groupby(['Country Name']).count()
nb_col_an = data_c[4:].shape[1]
nb_indic = series_c['Indicator Code'].shape[0]
nb_max = (nb_col_an*nb_indic)
tab = gp[gp.columns[3:]].sum(axis=1)*100/nb_max
tab.sort_values(ascending=False,inplace=True)
x=tab.index
xlab=[my_str[:8]+"..." if len(my_str)>8 else my_str for my_str in x]
y=tab
plot1 = plt.subplot(2,1,1)
basic_plot("bar", plot1, xlab, y, '', "Tous les pays", "% de cases indicateur/année renseignées", "% Indicateurs renseignés sur toutes les années \n(Data)", 5)
plt.show()
# tableau du pourcentage d'indicateurs renseignés par pays et par région ()
fig2 = plt.figure(figsize = (30,10))
tab_df = [data_c.groupby(['Region', 'Country Name']).count().loc[reg][li_annees] for reg in li_region]
n = 4 # nombre de colonnes d'affichage en largeur
tab_plot = []
for i in range(len(tab_df)):
x=tab_df[i].index
xlab=[my_str[:8]+"..." if len(my_str)>8 else my_str for my_str in x]
y=tab_df[i].sum(axis=1) # nombre d'indicateurs renseignés
y.sort_values(ascending=False,inplace=True)
tab_plot.append(plt.subplot((len(tab_df)+1)//n+1,n,i+1))
basic_plot("bar", tab_plot[i], xlab, y, '', "Pays de la région\n'"+ li_region[i] + "'", "Nbe ind renseignés", "", i)
plt.ylim(0,35000)
plt.gcf().subplots_adjust(left = 0.1, bottom = 0.2, right = 0.7, top = 1.2, wspace = 0.3, hspace = 0.3)
plt.show()
Quelle que soit la région considérée, la plupart des pays ont plus de 5000 indicateurs renseignés, toutes années confondues.
# Pays ayant moins de pct*100 % d'indicateurs renseignés, par région
def nbe_pays_inf_pct (pct, nb_ind) :
return [tab_df[i][tab_df[i].sum(axis=1)<pct*(nb_ind*len(li_annees))].shape[0] for i in range(len(li_region))]
fig = plt.figure(figsize = (20,5))
plot1 = plt.subplot(1,2,1)
barWidth = 0.25
x = li_region
xlab = [my_str[:10]+"..." if len(my_str)>8 else my_str for my_str in x]
nb_indic = len(data_c["Indicator Code"].unique())
i=0
for pct in [0.1,0.05,0.02,0.01] :
plot1.bar(np.arange(len(xlab))+i*barWidth, nbe_pays_inf_pct(pct,nb_indic),\
color=colors[i], width=barWidth, ec='k', label = "- de %.0f"%(pct*100) + " %")
i+=1
plt.xticks([r + barWidth for r in range(len(xlab))], xlab, rotation=85 , fontsize = 14)
#plot1.set_xlabel(fontsize = 14), plot1.set_ylabel(fontsize = 14)
plot1.set_title("Nbe de pays ayant moins de x %\nde cases indicateur-année renseignées", fontsize = 18, fontweight = 'bold')
plt.grid(color='grey', linestyle='dotted'), plt.legend()
plt.margins(0.2), plt.subplots_adjust(bottom=0.15)
plot2 = plt.subplot(1,2,2)
x = np.linspace(0,10, 11)
y = [sum(nbe_pays_inf_pct(val/100, nb_indic)) for val in x]
plot2.plot(x,y, '-o', color = 'b')
basic_plot("plot", plot2, x, y, x, "pourcentage seuil x ",\
"Nbe de pays", "Nbe de pays ayant moins de x% \nde cases indicateur-année renseignées" , i)
plt.show()
On pourrait enlever les pays qui ont moins de 2% de leurs indicateurs renseignés (moins de 20 pays).
# Nombre de lignes restantes (non entièrement vides) après sélection des années
borne_annee_min = [1959,1964,1969,1974,1979,1984,1989,1994,1999,2004,2009,2014]
y=[]
for annee_min in borne_annee_min:
new_li_annees = [annee for annee in list(li_annees) if int(annee)>annee_min and int(annee)<2018]
y.append(data_c[new_li_annees].dropna(how = 'all', inplace = False).shape[0])
fig = plt.figure(figsize = (18,3))
x=borne_annee_min
xlab=["["+str(annee)+",2018]" for annee in x]
plot1 = plt.subplot(1,2,1)
basic_plot("plot", plot1, xlab, y, xlab, "", "lignes restantes", \
"Lignes non entièrement nulles\nselon la plage de temps considérée", 0)
plot1.set_ylim(100000,data_c[li_annees].dropna(how = 'all', inplace = False).shape[0]*1.05)
Lorsque l'on écarte les données avant 1990 environ, le nombre de lignes entièrement nulles commence à croître. Or la part de la population ayant entre 25 et 26 ans aujourd'hui est née entre 1993 et 1994. Pour notre étude, il n'est pas pertinent d'utiliser des données avant ces années. On retire donc toutes les années avant 1990. On retirera ensuite les lignes qui ne contiennent pas de données pour les années 1990-2018.
# Nbe de pays ayant un nbe d'indicateurs supérieur à n en fonction des années
nb_ind_cnt = data_c.groupby(['Country Name']).count()[li_annees]
def calc_nb_pay_rens (tab_n, years): # prend un tableau de seuils entiers et un tableau d'années
tab = [ [nb_ind_cnt[nb_ind_cnt[str(i)]>j].index.size for i in years] for j in tab_n ]
res = np.array(tab).T
return res
fig = plt.figure(figsize = (18,5))
countrys = [nb_ind_cnt.index[i][0] + " - " + nb_ind_cnt.index[i][1] for i in range(nb_ind_cnt.index.size)]
tab_n = [0,2,10,50,100, 200, 500]
x = [int(y) for y in li_annees]
y = calc_nb_pay_rens(tab_n,x)
colors = ["#bd5db0","#70a845","#727bcc","#b49242","#cc566c","#4aad92","#ca6037"]
labels = ["i="+str(i) for i in tab_n]
plot1 = plt.subplot(1,2,1)
[plot1.plot(x, y[:,i], '-o', label = labels[i], color = colors[i]) for i in range(len(tab_n))]
plot1.set_ylim(0,230)
plot1.set_xlabel("années", fontsize = 14), plot1.set_ylabel("nbe de pays", fontsize = 14)
plot1.set_title("Pays ayant plus de i indicateurs", fontsize = 18, fontweight = 'bold')
plot1.legend(loc = 'lower right'), plt.grid()
plot2 = plt.subplot(1,2,2)
[plot2.plot(x, y[:,i], '-o', label = labels[i], color = colors[i]) for i in range(len(tab_n))]
plot2.set_xlim(1980,2018), plot2.set_ylim(75,220)
plot2.set_xlabel("années", fontsize = 14), plot2.set_ylabel("nbe de pays", fontsize = 14)
plot2.set_title("Pays ayant plus de i indicateurs (zoom)", fontsize = 18, fontweight = 'bold')
plot2.legend(loc = 'lower right'), plt.grid()
plt.show()
# Nbe d'indicateurs existant pour plus de n pays selon les années
nb_pay_cnt = data_c.groupby(['Indicator Name']).count()[li_annees]
def calc_nb_ind_rens (tab_n, years): # prend un tableau de seuils entiers et un tableau d'années
tab = [ [nb_pay_cnt[nb_pay_cnt[str(i)]>j].index.size for i in years] for j in tab_n ]
res = np.array(tab).T
return res
fig = plt.figure(figsize = (18,5))
countrys = [nb_ind_cnt.index[i][0] + " - " + nb_ind_cnt.index[i][1] for i in range(nb_ind_cnt.index.size)]
tab_n = [20,50,70,100, 200]
x = [int(y) for y in li_annees] # liste des anneés
y = calc_nb_ind_rens(tab_n,x)
colors = ["#bd5db0","#70a845","#727bcc","#b49242","#cc566c","#4aad92","#ca6037"]
labels = ["i="+str(i) for i in tab_n]
plot1 = plt.subplot(1,2,1)
[plot1.plot(x, y[:,i], '-o', label = labels[i], color = colors[i]) for i in range(len(tab_n))]
plot1.set_ylim(0,2000)
plot1.set_xlabel("années", fontsize = 14), plot1.set_ylabel("nbe d'indicateurs", fontsize = 14)
plot1.set_title("Indic existant pour + de i pays", fontsize = 18, fontweight = 'bold')
plot1.legend(loc = 'upper right'), plt.grid()
plot2 = plt.subplot(1,2,2)
[plot2.plot(x, y[:,i], '-o', label = labels[i], color = colors[i]) for i in range(len(tab_n))]
plot2.set_xlim(1980,2018), #plot2.set_ylim(75,220)
plot2.set_xlabel("années", fontsize = 14), plot2.set_ylabel("nbe d'indicateurs", fontsize = 14)
plot2.set_title("Indic existant pour + de i pays (zoom)", fontsize = 18, fontweight = 'bold')
plot2.legend(loc = 'upper left'), plt.grid()
plt.show()
L'exploration ci-dessus nous permet de prendre des décisions par rapport aux années et aux pays sous-remplis :
# Suppression des colonnes années inutiles, et des lignes entièrement vides après opération
li_col_supp = [annee for annee in list(li_annees) if int(annee)<1990 or int(annee)>2015] # colonnes à supprimer
print("Taille de la dataframe 'data_c' avant suppression des colonnes : ", data_c.shape)
data_c.drop(columns = li_col_supp, inplace = True)
print("Taille de la dataframe 'data_c' après suppression des colonnes : ", data_c.shape)
li_annees_sel = sorted(Diff(li_annees, li_col_supp)[0]) # colonnes à conserver
lign_supp = sorted(Diff(data_c[li_annees_sel].dropna\
(how='all', axis = 0, inplace=False).index, data_c.index)[1]) # index des lignes vides à supprimer
data_c.drop(index = lign_supp, inplace = True)
print("Taille de la dataframe 'data_c' après suppression des lignes vides : ", data_c.shape)
# Suppression des pays ayant moins de 2% de cases indicateur/année renseignées
# (soit environ 2300 pour 32 années et 3665 indicateurs)
gp = data_c.groupby(['Country Name']).count() # nbe de cases renseignées pour chaque pays et chaque année
gp_sum = gp[gp.columns[5:]].sum(axis=1) # nbe de cases renseignées pour chaque pays (ttes années cumulées)
pays_supp = list(gp_sum[gp_sum<2300].index) # liste des pays à supprimer (16)
tab_index_supp = [list(data_c[data_c["Country Name"]==pays].index) for pays in pays_supp] # tab d'index des lignes à suprimer
li_lign_supp = sorted([j for index in tab_index_supp for j in index]) # liste des lignes à supprimer
print("Suppression de {} pays, (soit {} lignes) Ã savoir :\n{}".format(len(pays_supp), len(li_lign_supp), pays_supp))
print("Taille de la dataframe 'data_c' avant suppression : ", data_c.shape)
data_c.drop(index = li_lign_supp, inplace = True)
print("Taille de la dataframe 'data_c' après suppression : ", data_c.shape)
On s'intéresse maintenant aux indicateurs peu renseignés. Y a-t-il des indicateurs trop peu renseignés dans la plage de temps qui nous intéresse (1990-2015) ? Le manque d'information concerne-t-il en particulier les années ou les pays ?
# Exploration des indicateurs disponibles pour un nombre insuffisant de pays ou d'années
gp = data_c.groupby(['Indicator Code']).count() # nbe de cases renseignées pour chaque indicateur et chaque année
gp_sum = gp[gp.columns[5:]].sum(axis=1) # nbe de cases renseignées pour chaque indicateur (ttes années cumulées)
#np.sum(gp_sum) # 3043320 cases en tout
#len(data_c['Indicator Code'].unique()) # 3647 indicateurs différents
#----------------------------------
fig1 = plt.figure(figsize = (15,3))
plot1 = plt.subplot(1,2,1)
# échantillon de 3043320 cases remplies, 6848 cases maximum par indicateur
plot1.hist(gp_sum, bins = 20, fc = 'None', ec = 'k', label='bins = 20')
plot1.hist(gp_sum, bins = 60, fc = 'b', alpha = 0.5, ec = 'k', label='bins = 60')
plt.xlabel("Nombre de cases remplies"), plt.ylabel("Nbe d'indicateurs")
plt.title('Répartition du nombre\nde cases remplies par indicateur')
plt.grid(True), plt.legend()
plt.text(1000, 1000,"éch : 3 043 320 cases\n6848 cases max par indic\n3647 indicateurs différents")
#plt.xlim(40, 160), plt.ylim(0, 0.03)
#---
plot2 = plt.subplot(1,2,2)
plot2.hist(gp_sum, bins = 100, fc = 'None', ec = 'k', label='bins = 100')
plot2.hist(gp_sum, bins = 400, fc = 'b', ec = 'k', label='bins = 400')
plt.xlabel("Nombre de cases remplies"), plt.ylabel("Nbe d'indicateurs")
plt.xlim(-10, 1000), plt.ylim(0, 1300), plt.grid(True) , plt.legend()
plt.title('Répartition du nombre de cases\nremplies par indicateur (zoom)')
plt.show()
#----------------------------------
#----------------------------------
fig2 = plt.figure(figsize = (20,2))
plot3 = plt.subplot(1,2,1)
plot3.hist(gp_sum, bins = 3700, fc = 'b', alpha = 0.2, ec = 'b', density=False,\
histtype='stepfilled', cumulative=True, label='bins = max')
plot3.hist(gp_sum, bins = 15, fc = 'r', alpha = 0.5, ec = 'k', density=False,\
histtype='step', cumulative=True, label='bins = 15')
plt.xlabel("Nombre de cases remplies"), plt.ylabel("% d'indicateurs")
plt.grid(True), plt.legend(loc='lower right')#, plt.xlim(-20, 1000), plt.ylim(0, 1000)
plt.title('Répartition du nombre de cases\nremplies par indicateur')
#---
plot4 = plt.subplot(1,2,2)
plot4.hist(gp_sum, bins = 3700, fc = 'b', alpha = 0.2, ec = 'b', density=True,\
histtype='stepfilled', cumulative=True, label='bins = max')
plot4.hist(gp_sum, bins = 15, fc = 'r', alpha = 0.5, ec = 'k', density=True,\
histtype='step', cumulative=True, label='bins = 15')
plt.xlabel("Nombre de cases remplies"), plt.ylabel("% d'indicateurs")
plt.grid(True), plt.legend(loc='lower right'), plt.xlim(-20, 1000), plt.ylim(0, 0.8)
plt.title('Répartition du nombre de cases\nremplies par indicateur (zoom)')
plt.gcf().subplots_adjust(left = 0.1, bottom = 0.2, right = 0.7, top = 1.2, wspace = 0.3, hspace = 0.5)
plt.show()
#----------------------------------
Il y a plus de 2300 indicateurs sur 3647 (63%) qui ont moins de 700 cases remplies. Intéressons-nous au taux de remplissage de ces indicateurs en particulier.
li_ind_m700 = gp_sum[gp_sum.values<700].index # liste des codes des 2332 indicateurs concernés
df_ind_m700 = data_c[data_c["Indicator Code"].isin(li_ind_m700)] # 126805 lignes concernées
ind_uni = df_ind_m700["Indicator Code"].unique() # liste des noms des indicateurs concernés
# nombre d'années calc par indic et par pays
nb_ann = df_ind_m700[df_ind_m700.columns[5:]].count(axis=1) # (25 bins de 2 Ã 26)
# nombre de pays différents par indicateur (pour au moins une année)
tab = df_ind_m700.groupby(["Indicator Code", "Country Code"])[li_annees_sel].count().sum(axis=1) # nbe val par ind/pay
nb_pay = [len(tab.loc[code]) for code in ind_uni] # liste des nbes de pays ayant au -1 valeur par indic (pas de ligne nulle)
#nb_pay = [len(tab.loc[code][(tab.loc[code]!=0).values]) for code in ind_uni] # en tenant compte d'éventuelles lignes nulles
#----------------
fig = plt.figure(figsize = (16,4))
#----------------
plot1 = plt.subplot(1,2,1)
plot1.hist(nb_ann, bins = 24, fc = 'b', alpha = 1, ec = 'b', density=True,\
histtype='step', cumulative=True, label='bins = max')
# plot1.hist(nb_ann, bins = 15, fc = 'r', alpha = 0.5, ec = 'k', density=True,\
# histtype='step', cumulative=True, label='bins = 15')
plt.title("Répartition du nombre d'années par combinaison\nindicateur/pays (indic - de 700 cases remplies)")
plt.xlabel("Nb d'années"), plt.ylabel("% d'indicateur/pays")
plt.xlim(1, 27), plt.ylim(0, 1.1), plt.grid(), plt.legend(loc='lower right')
#----------------
plot2 = plt.subplot(1,2,2)
plot2.hist(nb_pay, bins = 215, fc = 'b', alpha = 1, ec = 'b', density=False,\
histtype='step', cumulative=True, label='bins = max')
# plot1.hist(nb_ann, bins = 15, fc = 'r', alpha = 0.5, ec = 'k', density=True,\
# histtype='step', cumulative=True, label='bins = 15')
plt.title('Répartition du nombre de pays différents (au moins une valeur)\npar indicateur (indic - de 700 cases remplies)')
plt.xlabel("Nb de pays"), plt.ylabel("Nbe d'indicateurs")
plt.xlim(0, 170), plt.ylim(0, 2500), plt.grid(), plt.legend(loc='lower right')
plt.show()
Précisions au sujet des indicateurs peu remplis (moins de 700 cases sur 26*214 = 5564 cases)
######### ATTENTION, éliminé toutes les combis ayant moins de 3 années calculées
li_supp = data_c[data_c[data_c.columns[6:]].count(axis=1)<3].index # 37634, 76279 = 113913 lignes à supprimer
print("Taille de la dataframe 'data_c' avant suppression des lignes indicateurs : ", data_c.shape)
data_c.drop(index = li_supp, inplace = True)
print("Taille de la dataframe 'data_c' après suppression des lignes : ", data_c.shape)
### Nouvelle heatmap du nombre d'indicateurs non nuls (pays/années)
nb_ind_cnt = data_c.groupby(['Country Name']).count()[li_annees_sel]
nb_ind_cnt.head()
data_c.to_csv('../DONNEES/data_c.csv', index = False)
# Tableau des nombres d'indicateurs dispo pour chaque pays et chaque année
sns.set(font_scale=1.8)
fig = plt.figure(figsize = (28,105))
heat_map = sns.heatmap(nb_ind_cnt)
# Enquête sur les 10 topics disparus suite à l'élimination des pays, années, indicateurs sous-remplis
li_top_data_c = data_c["Topic"].unique()
li_top_data = pd.merge(data, series, left_on="Indicator Code", right_on="Series Code")["Topic"].unique()
li_topics_supp = list(Diff(li_top_data, li_top_data_c)[0])
data_plus = pd.merge(data, series, left_on="Indicator Code", right_on="Series Code")
li_topics_supp
# sélection des index des topics éliminés
selec_ind = data_plus.isin({'Topic': li_topics_supp}).replace(False, np.nan).dropna(how='all').index
# Sur quelles années portent les données des topics éliminés ?
#data_plus.iloc[selec_ind][li_annees].count()
# 2009 105 - 2010 176- 2011 116 - 2012 701 - 2013 785 - 2014 502- 2015 410 - 2016 391 - 2017 143
# seulement des données de 2009 à 2017
# Tableau des nombres de valeurs d'indicateurs dispo par topic
sns.set(font_scale=1.2)
gb = data_c[['Topic'] + li_annees_sel].groupby('Topic').count()#.sum(axis = 1) # 27 topics seulement
fig = plt.figure(figsize = (15,6))
heat_map = sns.heatmap(gb.T)
# format text labels
xticklabels = [] # fmt = '{:0.2f}'
for item in heat_map.get_xticklabels():
item.set_text(item.get_text()[:20]+"...") #(fmt.format(float(item.get_text())))
xticklabels += [item]
heat_map.set_xticklabels(xticklabels)
plt.show()
Afin de faciliter la recherche des outliers, les calculs de corrélation entre les différents indicateurs, l'ANOVA et les tracés des indicateurs pertinents, on effectue les opérations suivantes :
# 'Topic', 'Indicator Code','Indicator Name', 'Region', 'Country Name', 'Country Code'
data_c_mod = data_c[['Topic','Indicator Code','Region','Country Name']+li_annees_sel].copy(deep = True)
data_c_mod.set_index(['Topic','Indicator Code','Region','Country Name'], inplace = True)
data_c_mod.columns = pd.MultiIndex.from_product([data_c_mod.columns, ['val']], names = ['Year', 'nom'])
data_c_mod.columns = data_c_mod.columns.swaplevel(0, 1)
data_c_mod = data_c_mod.unstack(['Region','Country Name'])
data_c_mod.columns = data_c_mod.columns.droplevel()
data_c_mod.sort_index(inplace=True)
data_c_mod = data_c_mod.dropna(how = 'all', inplace = False, axis = 0)
data_c_mod = data_c_mod.T.dropna(how = 'all', inplace = False, axis = 0)
data_c_mod.sort_index(inplace=True)
data_c_mod.shape # 5148,2310 -> 11Â 891Â 880 cases
data_c_mod.head()
#data_c_mod[('Secondary', 'UIS.DR.2.GPV.G4.F')]
mi_col = data_c_mod.columns
mi_col.get_level_values(0) # Tous les topics des indicateurs
mi_col.get_level_values(1) # Tous les indicateurs
data_c_mod.to_csv('../DONNEES/data_c_mod.csv')
# Pas terrible l'enregistrement d'un fichier csv avec des multiindex...
# test = pd.read_csv('../DONNEES/data_c_mod.csv')
# test.head
print("Nombre de valeurs d'indicateurs non vides avant modification :\n{}, pour une taille de tableau de {} = {} cases"\
.format(np.sum(~np.isnan(data_c[li_annees_sel].values)),data_c.shape,data_c.shape[0]*data_c.shape[1])) # 2 853 128
print("Nombre de valeurs d'indicateurs non vides après modification :\n{}, pour une taille de tableau de {} = {} cases"\
.format(np.sum(~np.isnan(data_c_mod.values)),data_c_mod.shape,data_c_mod.shape[0]*data_c_mod.shape[1])) # 2 853 128 sur 11Â 891Â 880 cases
On veut évaluer la corrélation de différents indicateurs, mais il faut comparer leurs valeurs pour les mêmes combinaisons pays-année, qui ne sont pas toujours disponibles.
Dans le tableau ci-dessus, le nombre de données communes (renseignées pour les deux indicateurs comparés) est affiché dans les cases, et la couleur indique le degré de corrélation.
Ces tableaux pourront nous permettre d'identifier les indicateurs fortement corrélés, c'est-à -dire dont les tendances au cours des années sont similaires pour les différents pays.
def impr_tab_corr(nom_topic,val_min,val_max,tuple_width_length):
# indicateurs du topic choisi pour toutes les années, tous les pays
echant = data_c_mod.loc[idx[li_annees_sel,:,:], idx[nom_topic,:]] # ['1990','1995']
echant = echant[echant.columns[val_min:val_max]]
# liste des indicateurs
li_indic = [c2 for c1,c2 in echant.columns]
li_indic2 = [(c1,c2) for c1,c2 in echant.columns]
# Nombre de valeurs par colonne
li_nb_val = [echant[tucol].count() for tucol in echant.columns]
# Nombre de valeurs renseignées communes pour chaque combinaison de deux indicateurs
echant_b = ~np.isnan(echant) # valeur 'null' ou pas
nb_val_comm = np.array([[np.sum(echant_b[j]&echant_b[i]) for i in li_indic2]for j in li_indic2])
my_corr = echant.corr()
# affichage tableau
sns.set(font_scale=1.2)
sns.set(style="whitegrid")
fig, ax = plt.subplots(figsize = tuple_width_length)
mask = np.zeros_like(my_corr, dtype=np.bool) # Generate a mask for the upper triangle
mask[np.triu_indices_from(mask)] = True
palette = sns.diverging_palette(100, 10, as_cmap=True) # palette divergente sur mesure
#li_indic = [t2 for t1,t2 in my_corr.columns.values]
ax = sns.heatmap(my_corr, mask=mask, cmap=palette, vmin=-1, vmax=1, center=0,
annot = nb_val_comm, fmt = '', # '.2f'
square = False, linewidths=.5, linecolor = 'lightgrey',
cbar_kws = {"shrink": .7, 'label': '\ncoeff de corrélation\n(Pearson)'}, # pour le aspect ratio de la légende
xticklabels = li_indic, yticklabels = li_indic)
ax.tick_params(top=False, bottom=True, labeltop=False, labelbottom=True)
plt.setp(ax.get_xticklabels(), rotation=25, ha="right",rotation_mode="anchor")
ax.set_title("Corrélation entre indicateurs pour le topic '" + nom_topic + "'\n(Nbe de données communes)", fontweight = 'bold')
plt.show()
impr_tab_corr('Pre-Primary',0,14, (10,4))
impr_tab_corr('Attainment',0,31, (18,6))
impr_tab_corr('Attainment',59,91, (18,6))
impr_tab_corr('Secondary',0,30, (18,6))
Avant d'éliminer ou de remplacer les outliers, on voudrait en connaîre le nombre approximatif en fonction du nombre de sigma choisi pour le seuil. On trace les histogrammes du nombre d'outliers par indicateur pour un seuil de 3, 5, 10 et 20 sigmas :
# Prend un tableau de valeurs, calcule la moyenne, l'écart type
# et renvoie les valeurs au-delà ou en-deça de x fois l'écart-type
# def detOutliers_col(df,col,n):
# moy = df[col].mean()
# std = df[col].std()
# out_val = [val for val in df[col].values if ((val<moy-(n*std)) or (val>moy+(n*std)))]
# return df[df[col].isin(out_val)].index, out_val # renvoie les index de la ligne contenant les outliers, et leur valeur
def detOutliers_df(df_val,n): # prend en entrée une dataframe de toutes les valeurs d'un indicateur et le nbe de sigmas seuil
moy = np.nanmean(df_val)
std = np.nanstd(df_val)
v_min = moy-(n*std)
v_max = moy+(n*std)
df_flat = df_val.flatten()[~np.isnan(df_val.flatten())]
out_val = [val for val in df_flat if (val<v_min or val>v_max)]
# index et colonne remplissant la condition, valeur correspondante... Ã faire
return out_val # renvoie les outliers
#Détermination du nombre de sigmas à prendre en compte pour la détection des outliers
li_ind_uni = data_c['Indicator Code'].unique()
tab_df = [data_c[data_c['Indicator Code']==ind][li_annees_sel] for ind in li_ind_uni]
# tableau du nombre d'outliers pour tous les indicateurs avec n sigma
nb_std = [3,5,10,20]
tab_nb_out = [[len(detOutliers_df(df.values,n)) for df in tab_df] for n in nb_std]
# Nombre d'outliers par indicateur pour un nombre n d'écart-type
sns.set_style("whitegrid")
fig = plt.figure(figsize = (18,8))
tab_plot = []
for i in range(len(tab_nb_out)):
tab_plot.append(plt.subplot(1,4,i+1))
tab_plot[i].hist(tab_nb_out[i], bins = 30, color = colors[i],\
label = "total =\n"+str(sum(tab_nb_out[i])))
plt.xlabel("Nbe d'outliers", fontsize=14), plt.ylabel("Nbe d'indicateurs", fontsize=14)
#plt.xlim(0, 120)
y_lim = (np.histogram(tab_nb_out[i], bins = 30)[0][1]*1.1)
my_y_lim = y_lim if y_lim != 0 else 20
plt.ylim(0, my_y_lim)
#plt.text(0,my_y_lim*0.05, "total = "+str(sum(tab_nb_out[i])), fontsize=14)
plt.title(str(nb_std[i])+" sigmas", fontsize=14)
plt.grid(True), plt.legend(fontsize=12)
plt.gcf().subplots_adjust(left = 0.25, bottom = 0.5, right = 1.1, top = 0.89, wspace = 0.25, hspace = 0.2)
fig.suptitle("Répartition du nombre d'outliers selon le nombre de sigmas (2300 indicateurs en tout)",
fontsize=16)
plt.show()
#-----------------------------
fig = plt.figure(figsize = (15,3))
plot5 = plt.subplot(1,1,1)
# tableau du nombre d'outliers pour tous les indicateurs avec n sigma
nb_std = [3,3.5,4,5,6,7,8,9,10,12,14,16,18,20]
nb_out_std = [sum([len(detOutliers_df(df.values,n)) for df in tab_df]) for n in nb_std]
plot5.plot (nb_std, nb_out_std, '-o', label = "nbe d'outliers", color = 'grey', markerfacecolor = 'k')
#plot5.set_xlim(1980,2018), #plot5.set_ylim(75,220)
plot5.set_xlabel("nombre de sigmas", fontsize = 14), plot5.set_ylabel("Nombre d'outliers", fontsize = 14)
plot5.set_title("Nombre d'outliers selon le critère", fontsize = 18, fontweight = 'bold')
plot5.legend(loc = 'upper right'), plt.grid()
plt.show()
On souhaite éliminer les valeurs aberrantes (outliers) au-delà et en deça de 3 sigmas. On calcule le zscore de tous les indicateurs en se basant sur l'ensemble des valeurs qu'il peut prendre selon les années ([1995;2015]) et les pays (214 pays sélectionnés).
# calcule le zscore colonne par colonne, renvoie les z-scores ligne par ligne
data_c_mod_z = data_c_mod.copy(deep=True)
# Calcul pour chaque indicateur du z-score et remplissage d'une nouvelle dataframe
for (c1,c2) in data_c_mod.columns :
data_c_mod_z[(c1,c2)] = (data_c_mod[(c1,c2)] - data_c_mod[(c1,c2)].mean()) / data_c_mod[(c1,c2)].std(ddof=0)
# crée une nouvelle dataframe sans outliers
data_c_mod_wo_out = data_c_mod.copy(deep=True)
#np.warnings.filterwarnings('ignore')
data_c_mod_wo_out = data_c_mod.where(np.abs(data_c_mod_z.values) < 3)
# comparaison du nombre des valeurs qui ne sont pas 'null' dans les dataframes données et zscore
print("nb d'outliers retirés : {}"\
.format(sum(sum(~np.isnan(data_c_mod_z.values)))-sum(sum(~np.isnan(data_c_mod_wo_out.values)))))
print("nb de nan crées par le calc du zscore : {}"\
.format(sum(sum(~np.isnan(data_c_mod.values)))-sum(sum(~np.isnan(data_c_mod_z.values)))))
sum(sum(~np.isnan(data_c_mod.values)))
Problème : apparemment, il existe des colonnes pour lesquelles l'écart-type est nul, ce qui renvoie un z-score null. Il y a 36 données qui sont dans ces colonnes.
# y a-t-il des lignes pour lesquelles le calcul du z-score donne lieu à la création d'un null ? lesquels ?
for j in range(data_c_mod.shape[1]): # colonnes
for i in range(data_c_mod.shape[0]): # lignes
if (~np.isnan(data_c_mod.values[i][j])) ^ ~(np.isnan(data_c_mod_z.values[i][j])): # logical_xor -> ^
print("col = "+str(j)+" -- ind = "+str(i)+" : ",data_c_mod.values[i][j]," , zscore : " ,data_c_mod_z.values[i][j])
else:
pass
On élimine les indicateurs pour lesquels, après la suppression des outliers, il n'y a aucune donnée 'non null'.
data_c_mod_wo_out.dropna(how = 'all', axis = 'columns', inplace = False).shape, data_c_mod_wo_out.shape
data_c_mod_wo_out.dropna(how = 'all', axis = 'columns', inplace = True)
On souhaite pouvoir quantifier la capacité de chaque indicateur à mettre en évidence des différences entre les pays qui soient éventuellement modélisables.
On cherche par un test statistique à vérifier l'hypothèse nulle d'égalité des moyennes des valeurs des différents pays. On réalise pour cela une ANOVA à un facteur (one-way ANOVA) suivie d'un test de Fisher. Pour chaque indicateur, on divise les données de chaque indicateur en classes regroupant les valeurs de chaque pays pour différentes années. On compare ensuite la variance de l'ensemble des données et la moyenne pondérée des variances des différentes classes en calculant un ratio F :
_F = Vinter/Vintra = (SCE/DDL_E)/(SCR/DDL_R),
où F = Vinter/Vintra = (SCE/DDL_E)/(SCR/DDL_R)
avec SCE : somme des écarts des carrés expliquée ou interclasse
et SCR : somme des écarts des carrés résiduelle ou intraclasse
et DDL_E et DDL_R les degrés de liberté respectifs._
Le rapport F suit une loi de Fisher, on peut donc obtenir, à partir des degrés de liberté du numérateur et du dénominateur, la p-valeur correspondant à la valeur de F obtenue, c'est-à -dire le pourcentage de chance pour que, avec une telle répartition de nos données, les moyennes soient vraiment distinctes. Plus F sera grand, moins les chances (p-valeurs) seront grandes, et plus F sera proche de 1 ,plus les chances seront grandes.
* Limitations de la démarche :
Pour appliquer ce test, il est cependant nécessaire que :
Or ici les données ne sont pas prélevées aléatoirement, et ne suivent sans doute pas une distribution normale. Elles dépendent en fait du paramètre année et sont susceptibles de suivre des tendances variables, ce qui se traduira par des variances différentes.
* Différentes approches pour la sélection des données :
Le test de Fisher et l'ANOVA peuvent être calculés avec des classes ayant des tailles d'échantillon différentes. Cependant, le fait que chaque valeur dans les classes corresponde à une année, il est probable que, la manière dont on sélectionnera les données pour le calcul de F influencera les résultats. Deux approches ont été adoptées pour la sélection :
Le rapport F n'est pas calculé s'il y a moins de 3 pays en tout ou si le nbe total de valeurs est inférieur à 2 fois le nombre des pays.
Trois fonctions sont définies ci-dessous :
def calc_Fisher_scipy (df, option): # sur une dataframe regroupant les données d'un seul indicateur
if option == 'opt': # on conserve toutes les données
df_mod = df.unstack('Year')
df_mod = df_mod.T
df_mod.columns = df_mod.columns.droplevel()
df_mod.dropna(how= 'all', axis = 1, inplace = True)
elif option == 'opt_bis': # on élimine les années vides, puis les pays n'ayant pas toutes les années
df_mod = df.unstack('Year')
df_mod = df_mod.dropna(how = 'all', axis = 1)
df_mod = df_mod.dropna(how = 'any', axis = 0)
df_mod = df_mod.T
df_mod.columns = df_mod.columns.droplevel()
### Vérif : ANOVA à un paramètre de la librairie scipy stats [entrée : liste val pays - sortie : F, p-valeur]
#Pour chaque classe, on garde toutes les données, en ignorant les nan
if df_mod.columns.size < 3: # pas de calcul s'il n'y a que 1 ou 2 pays
return np.nan ,np.nan,sum(sum(~np.isnan(df_mod.values))), df_mod.columns.size
else:
f, p = st.f_oneway(*[df_mod[pays][~df_mod[pays].isna()] for pays in df_mod.columns])
return f,p, sum(sum(~np.isnan(df_mod.values))), df_mod.columns.size
def calc_Fisher_all (df): # sur une dataframe regroupant les données d'un seul indicateur
MOY = df.mean() # moyenne de toutes les valeurs (années et pays)
Pays_moy = df.groupby(level="Country Name").mean() # moyenne des valeurs par pays (ttes les années)
Pays_count = df.groupby(level="Country Name").count() # nbe des valeurs par pays (ttes les années)
# Coeff de Fisher
# non calculé s'il y a - de 3 pays en tout ou si le nbe tot de valeurs < 3 fois le nombre des pays
if (len(Pays_moy) < 4) or ((df.count()-len(Pays_moy)) < 2*len(Pays_moy)):
return np.nan, sum(~np.isnan(df.values))
else :
# Somme des carrés des écarts expliquée = interclasse
SCE = np.nansum(Pays_count*(np.square(Pays_moy - MOY))) # Somme des carrés des écarts expliquée = interclasse
DDL_E = len(Pays_moy)-1 # Degré de liberté SCE (nombre de classes (pays) - 1)
# Somme des carrés des écarts résiduelle = intraclasse
SCR = 0
for pays in df.index.get_level_values(2).unique(): # pour chaque pays de la liste d'un indicateur
SCR += (np.nansum((np.square(df.loc[idx[:,:,pays]]-Pays_moy[pays]))))
# Degré de liberté SCR (somme des counts(années dispo) de chaque classe (pays) - nb de classes (pays))
DDL_R = df.count()-len(Pays_moy)
return (SCE/DDL_E)/(SCR/DDL_R), sum(~np.isnan(df.values))
def calc_Fisher_bis (df,option): # sur une dataframe regroupant les données d'un seul indicateur
if option == 'opt': # on conserve toutes les données
df_mod = df.unstack('Year')
df_mod = df_mod.T
df_mod.columns = df_mod.columns.droplevel()
df_mod.dropna(how= 'all', axis = 1, inplace = True)
elif option == 'opt_bis': # on élimine les années vides, puis les pays n'ayant pas toutes les années
df_mod = df.unstack('Year')
df_mod = df_mod.dropna(how = 'all', axis = 1)
df_mod = df_mod.dropna(how = 'any', axis = 0)
df_mod = df_mod.T
df_mod.columns = df_mod.columns.droplevel()
# F-score (non calculé s'il y a moins de 3 pays en tout ou s'il y a moins de 3 années)
if (df_mod.index.size < 4) or (df_mod.columns.size < 4):
return np.nan, sum(sum(~np.isnan(df_mod.values)))
else :
MOY = np.nanmean(df_mod.values) # moyenne de toutes les vzleurs (années-pays)
Pays_moy = df_mod.mean(axis=1) # moyenne des valeurs (ttes les années) par colonnes (pays)
Pays_count = df_mod.columns.size # nbe des valeurs par pays (nbe d'années)
# Somme des carrés des écarts expliquée = interclasse
SCE = np.sum(Pays_count*(np.square(Pays_moy - MOY)))
DDL_E = len(Pays_moy)-1 # Degré de liberté SCE (nombre de classes (pays) -1)
# Somme des carrés des écarts résiduelle = intraclasse
SCR = 0
for pays in df_mod.index: # pour chaque pays de la liste d'un indicateur
SCR += (np.sum((np.square(df_mod.loc[pays]-Pays_moy[pays]))))
# Degré de liberté SCR (somme des counts(années dispo) de chaque classe (pays) - nb de classes (pays))
DDL_R = df_mod.index.size*df_mod.columns.size - len(Pays_moy)
return (SCE/DDL_E)/(SCR/DDL_R), sum(sum(~np.isnan(df_mod.values)))
### Test sur un indicateur
df = data_c_mod_wo_out[data_c_mod_wo_out.columns[168]]
calc_Fisher_all (df), \
calc_Fisher_bis (df,'opt'), calc_Fisher_bis (df,'opt_bis'),\
calc_Fisher_scipy (df,'opt'), calc_Fisher_scipy (df,'opt_bis')
# Création d'une dataframe réunissant les scores et le nbe de données sur lesquelles ils ont été obtenus
Fisher1 = np.array([calc_Fisher_all(data_c_mod_wo_out[c1,c2]) for c1,c2 in data_c_mod_wo_out.columns]) #[0:10]
Fisher2 = np.array([calc_Fisher_bis(data_c_mod_wo_out[c1,c2],'opt') for c1,c2 in data_c_mod_wo_out.columns])
Fisher2_bis = np.array([calc_Fisher_bis(data_c_mod_wo_out[c1,c2],'opt_bis') for c1,c2 in data_c_mod_wo_out.columns])
Fisher3 = np.array([calc_Fisher_scipy(data_c_mod_wo_out[c1,c2],'opt') for c1,c2 in data_c_mod_wo_out.columns])
Fisher3_bis = np.array([calc_Fisher_scipy(data_c_mod_wo_out[c1,c2],'opt_bis') for c1,c2 in data_c_mod_wo_out.columns])
df_F_score = pd.DataFrame(data = {
"Topic" : data_c_mod_wo_out.columns.get_level_values(0),
"Indicator Name" : data_c_mod_wo_out.columns.get_level_values(1),
"calc_Fisher_scipy opt (f)" : Fisher3[:,0],
"calc_Fisher_scipy opt (p-val)" : Fisher3[:,1],
"calc_Fisher_scipy opt (nb)" : Fisher3[:,2],
"calc_Fisher_scipy opt (nb pays)" : Fisher3[:,3],
"calc_Fisher_scipy opt_bis (f)" : Fisher3_bis[:,0],
"calc_Fisher_scipy opt_bis (p-val)" : Fisher3_bis[:,1],
"calc_Fisher_scipy opt_bis (nb)" : Fisher3_bis[:,2],
"calc_Fisher_all (f)" : Fisher1[:,0],
"calc_Fisher_all (nb)" : Fisher1[:,1],
"calc_Fisher bis opt (f)" : Fisher2[:,0],
"calc_Fisher bis opt (nb)" : Fisher2[:,1],
"calc_Fisher bis opt_bis (f)" : Fisher2_bis[:,0],
"calc_Fisher bis opt_bis (nb)" : Fisher2_bis[:,1],
})
df_F_score.set_index(["Topic", "Indicator Name"], inplace = True)
# Dataframe des indicateurs, classés par la valeur de F et par topic
df_F_score.sort_values(by=['Topic','Indicator Name'], inplace = True)
# Affichage des résultats
fig = plt.figure(figsize = (16,8))
xy1 = df_F_score[["calc_Fisher_all (nb)", "calc_Fisher_all (f)"]].dropna(how = 'any', inplace = False)
xy2 = df_F_score[["calc_Fisher bis opt (nb)", "calc_Fisher bis opt (f)"]].dropna(how = 'any', inplace = False)
xy3 = df_F_score[["calc_Fisher_scipy opt (nb)","calc_Fisher_scipy opt (nb pays)",\
"calc_Fisher_scipy opt (f)"]].dropna(how = 'any', inplace = False)
ax1 = plt.subplot(2,3,1)
ax1 = sns.scatterplot(xy1["calc_Fisher_all (nb)"], xy1["calc_Fisher_all (f)"] , color = 'r', label = "calc_Fisher_all")
ax1.set_title("F-score = f(nbe de données)", fontsize = 16, fontweight = 'bold')
ax1.set_xlabel("Nombre de données", fontsize = 14)
ax1.set_ylabel("F-score", fontsize = 14)
ax2 = plt.subplot(2,3,2)
ax2 = sns.scatterplot(xy2["calc_Fisher bis opt (nb)"], xy2["calc_Fisher bis opt (f)"] , color = 'g', label = "calc_Fisher_bis")
ax2.set_title("F-score = f(nbe de données)", fontsize = 16, fontweight = 'bold')
ax2.set_xlabel("Nombre de données", fontsize = 14)
ax2.set_ylabel("F-score", fontsize = 14)
ax3 = plt.subplot(2,3,3)
ax3 = sns.scatterplot(xy3["calc_Fisher_scipy opt (nb)"], xy3["calc_Fisher_scipy opt (f)"] , color = 'k', label = "calc_Fisher_scipy")
ax3.set_title("F-score = f(nbe de données)", fontsize = 16, fontweight = 'bold')
ax3.set_xlabel("Nombre de données", fontsize = 14)
ax3.set_ylabel("f_oneway (f)", fontsize = 14)
ax4 = plt.subplot(2,3,4)
ax4 = sns.distplot(xy1["calc_Fisher_all (f)"].values, color = 'r', label = "calc_Fisher_all", norm_hist=False, kde=False)
ax4.set_title("Répartition des F-scores", fontsize = 16, fontweight = 'bold')
ax4.set_xlabel("F-score", fontsize = 14)
ax4.set_ylabel("Nbe de valeurs", fontsize = 14)
ax4.legend()
ax5 = plt.subplot(2,3,5)
ax5 = sns.distplot(xy2["calc_Fisher bis opt (f)"], color = 'g', label = "calc_Fisher bis", norm_hist=False, kde=False)
ax5.set_title("Répartition des F-scores", fontsize = 16, fontweight = 'bold')
ax5.set_xlabel("F-score bis", fontsize = 14)
ax5.set_ylabel("Nbe de valeurs", fontsize = 14)
ax5.legend()
ax6 = plt.subplot(2,3,6)
ax6 = sns.distplot(xy3["calc_Fisher_scipy opt (f)"], color = 'k', label = "calc_Fisher_scipy", norm_hist=False, kde=False)
ax6.set_title("Répartition des F-scores", fontsize = 16, fontweight = 'bold')
ax6.set_xlabel("f_oneway (f)", fontsize = 14)
ax6.set_ylabel("Nbe de valeurs", fontsize = 14)
ax6.legend()
plt.gcf().subplots_adjust(left = 0.1, bottom = 0.2, right = 0.7, top = 1.2, wspace = 0.3, hspace = 0.3)
plt.show()
fig = plt.figure(figsize = (16,8))
ax1 = plt.subplot(2,3,1)
ax1 = sns.scatterplot(xy3["calc_Fisher_scipy opt (nb pays)"], xy3["calc_Fisher_scipy opt (f)"] , color = 'r', label = "calc_Fisher_scipy opt")
ax1.set_title("F-score = f(nbe de pays)", fontsize = 16, fontweight = 'bold')
ax1.set_xlabel("Nombre de pays", fontsize = 14)
ax1.set_ylabel("F-score", fontsize = 14)
# répartition des scores
y1 = df_F_score["calc_Fisher_all (f)"][~np.isnan(df_F_score["calc_Fisher_all (f)"])]
y2 = df_F_score["calc_Fisher bis opt (f)"][~np.isnan(df_F_score["calc_Fisher bis opt (f)"])]
y3 = df_F_score["calc_Fisher_scipy opt (f)"][~np.isnan(df_F_score["calc_Fisher_scipy opt (f)"])]
fig = plt.figure(figsize = (15,3))
fig.suptitle('Répartition des valeurs des F-score', fontsize=16, fontweight = 'bold')
ax1 = plt.subplot(1,3,1)
ax1.hist(y1, bins=30, color = 'blue', label = "calc_Fisher_all")
ax1.legend()
ax2 = plt.subplot(1,3,2)
ax2.hist(y2, bins=30, color = 'red', label = "calc_Fisher bis opt")
ax2.legend()
ax3 = plt.subplot(1,3,3)
ax3.hist(y3, bins=30, color = 'black', label = "calc_Fisher_scipy opt")
ax3.legend()
plt.show()
# df_F_score2 = pd.DataFrame(data = {
# "Topic" : data_c_mod_wo_out.columns.get_level_values(0)[:10],
# "Indicator Name" : data_c_mod_wo_out.columns.get_level_values(1)[:10],
# })
# df_F_score2.set_index(["Topic", "Indicator Name"], inplace = True)
# df_F_score2.sort_values(by=['Topic','Indicator Name'], inplace = True)
# # On teste l'égalité des moyennes comme hypothèse nulle
# # y a-t-il des indics tels que f est très petit, et que la p-valeur recommence à diminuer ? :
# df_F_score2[df_F_score2["calc_Fisher_scipy opt(p-val)"]>0.001].dropna(how="any", inplace=False)
Il nous faut maintenant effectuer un choix des indicateurs pertinents à tracer. Les critères à reenir sont les suivants :
Afin d'avoir une première idée du contenu des indicateurs, traçons un nuage de mots-clés des noms des indicateurs :
list_pop = ["in", "of", "a", "and", "Per", "by", "the", "with", "to", "from",\
"for", "who", "on", "are"] # liste des mots non considérés
# génération dictionnaire effectif mots-clés
dic_occs = enum_mots_cmpt(data_c["Indicator Name"], 50) # Ã partir des noms d'indicateurs dans "Data"
dic_occs = filt_dict(dic_occs,list_pop) # filtrage des mots indésirables
nuageMots(dic_occs)
histMots(dic_occs)
Voici les sujets sur lesquels on cherche des informations :
public visé :
besoins en matière d'éducation :
possibilités de déploiement dans le pays :
possibilités de financement :
En balayant la liste des indicateurs disponibles, topic par topic, on réalise une première sélection des indicateurs pertinents à notre problématique :
# Recherche de mot-clés dans les indicateurs
# attention aux valeurs null dans les 'short definitions'
my_list = series["Short definition"].dropna(inplace = False)
tab = []
for i in my_list.index:
if ('household' in my_list.loc[i] and \
'funding' in my_list.loc[i] and\
'GDP' in my_list.loc[i] and\
'capita'in my_list.loc[i]) :
tab.append((i, series["Series Code"][i], series["Short definition"][i]))
tab
# Recherche de mot-clés dans les indicateurs
# attention aux valeurs null dans les 'short definitions'
my_list = series["Short definition"].dropna(inplace = False)
tab = []
for i in my_list.index:
if ('funding' in my_list.loc[i] and \
'household' in my_list.loc[i] and\
'GDP' in my_list.loc[i] and\
'capita'in my_list.loc[i]) :
tab.append((i, series["Series Code"][i], series["Short definition"][i]))
tab
Population ayant terminé le collège (lower secondary schooling)
Population actuellement au lycée (upper secondary schooling)
Population ayant obtenu le bac ou un diplôme d'études supérieure
Population déscolarisée, en âge d'être au lycée
Population actuellement à l'université ou dans des filières post-bac (tertiary schooling, post secondary/non tertiary)
Informations générales sur la population
accès à l'internet
accès à un ordinateur personnel
nbe d'enseignants par élève au lycée, à l'université
taux d'achèvement du cycle secondaire
part du budget familial consacré à l'éducation
pouvoir d'achat moyen
data_c_mod_wo_out_bis = data_c_mod.copy(deep = True)
data_c_mod_wo_out_bis.columns = data_c_mod_wo_out_bis.columns.droplevel()
data_c_mod_wo_out_bis.head(2)
# Vérification de la présence des indicateurs choisis dans la base
li_indic_o = series["Series Code"].unique()
li_indic_o_bis = data_c_mod_wo_out_bis.columns
li_ind_plot = ["UIS.E.3", "UIS.E.4", "SP.POP.1524.TO.UN",\
"IT.NET.USER.P2", "UIS.PTRHC.3", "UIS.PTRHC.56", "NY.GDP.PCAP.CD"]
print("Dans la liste d'origine des séries ?", [ind in li_indic_o for ind in li_ind_plot])
print("Dans la liste des séries nettoyées ?", [ind in li_indic_o_bis for ind in li_ind_plot])
# Affichage des F-score des indicateurs choisis
mask = [(code in li_ind_plot) for top,code in df_F_score.index]
df_F_score[mask]
Remarque : Tous les indicateurs ont des F-score élevés, donc les moyennes des valeurs par pays sont nettement distinctes.
# Création d'une dataframe restreinte (version multi-index)
data_plot = data_c_mod_wo_out_bis[li_ind_plot]
data_plot.head(2)
# Création d'une dataframe restreinte (version empilée en colonnes)
data_plot_hm = data_c_mod_wo_out_bis[li_ind_plot].copy(deep = True)
data_plot_hm = data_plot_hm.unstack('Year').stack('Indicator Code')
data_plot_hm.reset_index(inplace = True)
data_plot_hm.columns.names = [""]
data_plot_hm.head(1)
### Heatmap du nombre d'indicateurs non nuls (pays/années)
nb_ind_cnt = data_plot_hm.groupby(['Indicator Code']).count()[li_annees_sel]
# Tableau des nombres de pays ayant des valeurs dispo pour chaque indicateur et chaque année
fig = plt.figure(figsize = (18,3))
heat_map = sns.heatmap(nb_ind_cnt)
Tous les indicateurs choisis ont un bon taux de renseignement pour les années 1999-2014. Il manque des données pour les ratio élèves/professeurs avant 1999 (UIS.PTRHC.3 & UIS.PTRHC.56), ainsi que pour le nombre d'inscripion au lycée (UIS.E.3) et dans l'enseignement supérieur (UIS.E.4)
# Manipulation de la dataframe : empilement complet
data_plot_st = data_plot.copy(deep=True)
#set_index(["Region", "Country Name", "Indicator Code"], inplace = False)
data_plot_st.columns = pd.MultiIndex.from_product([data_plot_st.columns, ['val']], names = ['Indicator Code', 'nom'])
data_plot_st.columns = data_plot_st.columns.swaplevel(0, 1)
data_plot_st = data_plot_st.stack('Indicator Code')
data_plot_st = data_plot_st.reset_index(drop=False)
data_plot_st.head(2)
# ERREMENTS QUI FONCTIONNENT - Manipulation de la dataframe : itération sur le groupby 'Region'
internet_st = data_plot_st[data_plot_st["Indicator Code"]=='IT.NET.USER.P2']
internet_df_tab = [sub_df for name,sub_df in internet_st.groupby('Region')]
#liste des régions
li_reg = [name for name,sub_df in internet_st.groupby('Region')]
# moyenne de toutes les valeurs pour chaque région
moy_reg = np.array([df['val'].mean() for df in internet_df_tab])
# moyenne de toutes les valeurs des pays pour chaque région et chaque année
moy_reg_annees = np.array([[sub_df['val'].mean() for name,sub_df in internet_st.groupby('Year')]\
for df in internet_df_tab])
moy_reg.shape, moy_reg_annees.shape
Régions, par indicateur :
Pour une région par indicateur, pour les différents pays :
def label_graphs (x_lab, y_lab, title):
plt.xticks(rotation=25, fontsize = 12, ha='right', va='top'), plt.yticks(fontsize = 15)
plt.xlabel(x_lab, fontsize = 16, labelpad = 20)
plt.ylabel(y_lab, fontsize = 16, labelpad = 20)
plt.title(title, color='k',fontsize = 18, fontweight = 'bold')
# Sélection des données
UIE_E_st = data_plot_st[[i in ['UIS.E.3','UIS.E.4'] for i in data_plot_st["Indicator Code"]]]
SP_POP_st = data_c[data_c["Indicator Code"]=='SP.POP.1524.TO.UN']\
.drop(columns = ["Country Code","Indicator Name"], inplace = False)
SP_POP_st = SP_POP_st.set_index(["Region", "Country Name", "Indicator Code"], inplace = False)
SP_POP_st.columns = pd.MultiIndex.from_product([SP_POP_st.columns, ['val']], names = ['Year', 'nom'])
SP_POP_st.columns = SP_POP_st.columns.swaplevel(0, 1)
SP_POP_st = SP_POP_st.stack('Year')
SP_POP_st = SP_POP_st.reset_index(drop=False)
SP_POP_st.head(2)
li = ['2010','2011','2012','2013','2014']
data_li = UIE_E_st[[y in li for y in UIE_E_st["Year"]]]
data_li3 = data_li[data_li["Indicator Code"]=='UIS.E.3']
data_li4 = data_li[data_li["Indicator Code"]=='UIS.E.4']
data_li_EAP = data_li[data_li["Region"]=='East Asia & Pacific']
data_li_EAP3 = data_li3[data_li["Region"]=='East Asia & Pacific']
data_li_EAP4 = data_li4[data_li["Region"]=='East Asia & Pacific']
data_li_MENA = data_li[data_li["Region"]=='Middle East & North Africa']
data_li_MENA = data_li[data_li["Region"]=='Middle East & North Africa']
data_li_ECA = data_li[data_li["Region"]=='Europe & Central Asia']
data_li_ECA4 = data_li4[data_li["Region"]=='Europe & Central Asia']
data_li_NA = data_li[data_li["Region"]=='North America']
data_li_SSA = data_li[data_li["Region"]=='Sub-Saharan Africa']
data_li_SA = data_li[data_li["Region"]=='South Asia']
data_li_SA3 = data_li3[data_li["Region"]=='South Asia']
# moyennes années 2010 à 2014 pour le secondaire, tertiaire
moy_an_data_li_sec = data_li.groupby(['Country Name', "Indicator Code", 'Region']).mean()
moy_an_data_li_sec.index = moy_an_data_li_sec.index.swaplevel(0, 1).swaplevel(1, 2)
moy_an_data_li_sec = moy_an_data_li_sec.loc[idx['UIS.E.3',:,:]]
moy_an_data_li_sec = moy_an_data_li_sec.sort_values('val', ascending = False, inplace = False)
moy_an_data_li_sec = moy_an_data_li_sec.reset_index(drop = False)
moy_an_data_li_ter = data_li.groupby(['Country Name', "Indicator Code", 'Region']).mean()
moy_an_data_li_ter.index = moy_an_data_li_ter.index.swaplevel(0, 1).swaplevel(1, 2)
moy_an_data_li_ter = moy_an_data_li_ter.loc[idx['UIS.E.4',:,:]]
moy_an_data_li_ter = moy_an_data_li_ter.sort_values('val', ascending = False, inplace = False)
moy_an_data_li_ter = moy_an_data_li_ter.reset_index(drop = False)
moy_an_data_li_ter.head()
# Affichage
fig = plt.figure(figsize = (18, 8))
grid = plt.GridSpec(2, 4, wspace=0.5, hspace=0.6)
np.warnings.filterwarnings('ignore')
fig.suptitle("Nombre d'inscriptions - enseignement secondaire, tertiaire (UIS.E.3 & UIS.E.4)",
x=0.02, y=1.025, ha='left', va='top', fontsize=22, fontweight = 'bold')
ax1 = plt.subplot(grid[0, 0:2])
ax1 = sns.violinplot(x="Region", y='val',# hue="Indicator Code",\
data=data_li[data_li["Indicator Code"]=='UIS.E.3'],
split = False, inner="quartile", bw=.3, scale="count")
label_graphs("Régions","Nbe d'inscriptions", "Secondaire - Monde - 2010 à 2014")
#plt.legend(loc = 'upper left')
ax2 = plt.subplot(grid[0, 2:4])
ax2 = sns.violinplot(x="Region", y='val',# hue="Indicator Code",\
data=data_li[data_li["Indicator Code"]=='UIS.E.4'],
split = False, inner="quartile", bw=.3, scale="count")
label_graphs("Régions","Nbe d'inscriptions", "Tertiaire - Monde - 2010 à 2014")
#plt.legend(loc = 'upper left')
ax3 = plt.subplot(grid[1, 0:2])
ax3 = sns.barplot(x="Country Name", y="val", hue = "Region",dodge = False,
data=moy_an_data_li_sec.iloc[:13])
label_graphs("Pays","Nbe d'inscriptions",
"Secondaire, 12 pays aux plus gros effectifs - moyenne 2010-2014")
ax4 = plt.subplot(grid[1, 2:4])
ax4 = sns.barplot(x="Country Name", y="val", hue = "Region",dodge = False,
data=moy_an_data_li_ter.iloc[:13])
label_graphs("12 Pays max","Nbe d'inscriptions",
"Tertiaire, 12 pays aux plus gros effectifs - moyenne 2010-2014")
plt.subplots_adjust(left=-0.3, bottom=-0.2, right=0.9, top=0.9, wspace=0.05, hspace=0.1)
plt.savefig('01_public_vise.pdf')
plt.show()
# Sélecion des données
internet_st = data_plot_st[data_plot_st["Indicator Code"]=='IT.NET.USER.P2']
internet_st.head(2)
# Affichage
fig = plt.figure(figsize = (18,18))
grid = plt.GridSpec(3, 2, wspace=0.3, hspace=0.7)
np.warnings.filterwarnings('ignore')
li = ['2014','2004']
data_li = internet_st[[y in li for y in internet_st["Year"]]]
data_li_EAP = data_li[data_li["Region"]=='East Asia & Pacific']
data_li_MENA = data_li[data_li["Region"]=='Middle East & North Africa']
data_li_ECA = data_li[data_li["Region"]=='Europe & Central Asia']
ax1 = plt.subplot(grid[0, 0])
ax1 = sns.violinplot(x="Region", y='val', hue="Year",\
data=data_li, split = True, inner="quartile", bw=.3, scale="count")
label_graphs("Régions","utilisateurs pour 100 pers.",
"Utilisateurs d'internet pour 100 personnes\n(IT.NET.USER.P2) Monde")
ax2 = plt.subplot(grid[0, 1])
ax2 = sns.barplot(x="Country Name", y="val", hue = "Year",data=data_li_MENA.sort_values("val"))
label_graphs("Régions","utilisateurs pour 100 pers.",
"Utilisateurs d'internet pour 100 personnes\n(IT.NET.USER.P2) Middle East and North Africa")
ax3 = plt.subplot(grid[1, :])
ax3 = sns.barplot(x="Country Name", y="val", hue = "Year", data=data_li_ECA.sort_values("val"))
label_graphs("Pays","utilisateurs pour 100 pers.",
"Utilisateurs d'internet pour 100 personnes\n(IT.NET.USER.P2) Europe & Central Asia4")
ax4 = plt.subplot(grid[2, :])
ax4 = sns.barplot(x="Country Name", y="val", hue = "Year", data=data_li_EAP.sort_values("val"))
label_graphs("Pays","utilisateurs pour 100 pers.",
"Utilisateurs d'internet pour 100 personnes\n(IT.NET.USER.P2) East Asia and Pacific")
plt.subplots_adjust(left=-0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.05, hspace=0.05)
plt.savefig('02_internet.pdf')
plt.show()
# for reg in li_reg:
# ax1.annotate(reg, xy=(0, 0), xytext=(-17, 3),
# textcoords='offset points', ha='left', va='bottom' )
# Sélection des données
PTRHC_st = data_plot_st[[i in ['UIS.PTRHC.3','UIS.PTRHC.56'] for i in data_plot_st["Indicator Code"]]]
PTRHC_st.head(2)
# Affichage
fig = plt.figure(figsize = (18,18))
grid = plt.GridSpec(3, 4, wspace=0.5, hspace=0.6)
np.warnings.filterwarnings('ignore')
li = ['2010','2011','2012','2013','2014']
data_li = PTRHC_st[[y in li for y in PTRHC_st["Year"]]]
data_li_EAP = data_li[data_li["Region"]=='East Asia & Pacific']
data_li_MENA = data_li[data_li["Region"]=='Middle East & North Africa']
data_li_ECA = data_li[data_li["Region"]=='Europe & Central Asia']
data_li_NA = data_li[data_li["Region"]=='North America']
data_li_SSA = data_li[data_li["Region"]=='Sub-Saharan Africa']
data_li_SA = data_li[data_li["Region"]=='South Asia']
fig.suptitle("Ratio Elèves/Enseignants - enseignement secondaire, tertiaire (UIS.PTRHC.3 & UIS.PTRHC.56)",
x=0.02, y=0.95, ha='left', va='top', fontsize=22, fontweight = 'bold')
ax1 = plt.subplot(grid[0, 0:2])
ax1 = sns.violinplot(x="Region", y='val', hue="Indicator Code",\
data=data_li, split = True, inner="quartile", bw=.3, scale="count")
label_graphs("Régions","Nbe Elève/Prof.",
"Monde - 2010 Ã 2014")
plt.legend(loc = 'upper left')
ax2 = plt.subplot(grid[0, 2:4])
ax2 = sns.barplot(x="Country Name", y="val", hue = "Indicator Code",data=data_li_MENA.sort_values("val"))
label_graphs("Pays","Nbe Elève/Prof.",
"Middle East and North Africa - 2010 Ã 2014")
plt.legend(loc = 'upper right')
ax3 = plt.subplot(grid[1, :])
ax3 = sns.barplot(x="Country Name", y="val", hue = "Indicator Code", data=data_li_ECA.sort_values("val"))
label_graphs("Pays","Nbe Elève/Prof.",
"Europe & Central Asia - 2010 Ã 2014")
ax4 = plt.subplot(grid[2, 0:3])
ax4 = sns.barplot(x="Country Name", y="val", hue = "Indicator Code", data=data_li_SSA.sort_values("val"))
label_graphs("Pays","Nbe Elève/Prof.",
"Sub-Saharan Africa - 2010 Ã 2014")
plt.legend(loc = 'upper left')
ax5 = plt.subplot(grid[2, 3])
ax5 = sns.barplot(x="Country Name", y="val", hue = "Indicator Code", data=data_li_SA.sort_values("val"))
label_graphs("Pays","Nbe Elève/Prof.",
"South Asia - 2010 Ã 2014")
plt.legend(loc = 'lower right')
plt.subplots_adjust(left=-0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.05, hspace=0.05)
plt.savefig('03_education.pdf')
plt.show()
# Sélection des données
GDP_st = data_plot_st[data_plot_st["Indicator Code"]=='NY.GDP.PCAP.CD']
GDP_st.head(2)
# Affichage
fig = plt.figure(figsize = (18,18))
grid = plt.GridSpec(3, 4, wspace=0.5, hspace=0.7)
np.warnings.filterwarnings('ignore')
li = ['2014','2004']
data_li = GDP_st[[y in li for y in GDP_st["Year"]]]
data_li_EAP = data_li[data_li["Region"]=='East Asia & Pacific']
data_li_MENA = data_li[data_li["Region"]=='Middle East & North Africa']
data_li_ECA = data_li[data_li["Region"]=='Europe & Central Asia']
data_li_NA = data_li[data_li["Region"]=='North America']
ax1 = plt.subplot(grid[0, 0:2])
ax1 = sns.violinplot(x="Region", y='val', hue="Year",\
data=data_li, split = True, inner="quartile", bw=.3, scale="count")
label_graphs("Régions","PIB/hab.",
"PIB par habitant (NY.GDP.PCAP.CD)\nMonde")
ax2 = plt.subplot(grid[0, 2:4])
ax2 = sns.barplot(x="Country Name", y="val", hue = "Year",data=data_li_MENA.sort_values("val"))
label_graphs("Pays","PIB/hab.",
"PIB par habitant (NY.GDP.PCAP.CD)\n Middle East and North Africa")
ax3 = plt.subplot(grid[1, :])
ax3 = sns.barplot(x="Country Name", y="val", hue = "Year", data=data_li_ECA.sort_values("val"))
label_graphs("Pays","PIB/hab.",
"PIB par habitant (NY.GDP.PCAP.CD)\n Europe & Central Asia")
ax4 = plt.subplot(grid[2, 0:3])
ax4 = sns.barplot(x="Country Name", y="val", hue = "Year", data=data_li_EAP.sort_values("val"))
label_graphs("Pays","PIB/hab.",
"PIB par habitant (NY.GDP.PCAP.CD)\n East Asia and Pacific")
ax5 = plt.subplot(grid[2, 3])
ax5 = sns.barplot(x="Country Name", y="val", hue = "Year", data=data_li_NA.sort_values("val"))
label_graphs("Pays","PIB/hab.",
"PIB par habitant (NY.GDP.PCAP.CD)\n North America")
plt.subplots_adjust(left=-0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.05, hspace=0.05)
plt.savefig('04_economie.pdf')
plt.show()